diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000000..2ac65f2f5c7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +charset = utf-8 + +[*.yaml] +indent_size = 2 + +[tests/_files/*_result_cache.txt] +insert_final_newline = false + +[*.phpt] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes index 461090b7ecc..89d2d3aafb4 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,15 @@ +/.github export-ignore +/.phive export-ignore +/build export-ignore +/tools export-ignore +/tools/* binary +/tests export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.php-cs-fixer.dist.php export-ignore +/build.xml export-ignore +/phpstan.neon export-ignore +/phpunit.xml export-ignore + *.php diff=php diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 00000000000..ee242a803a0 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,28 @@ +# Contributor Code of Conduct + +As contributors and maintainers of this project, and in the interest of fostering an open and welcoming community, we pledge to respect all people who contribute through reporting issues, posting feature requests, updating documentation, submitting pull requests or patches, and other activities. + +We are committed to making participation in this project a harassment-free experience for everyone, regardless of level of experience, gender, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, or nationality. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery +* Personal attacks +* Trolling or insulting/derogatory comments +* Public or private harassment +* Publishing other's private information, such as physical or electronic + addresses, without explicit permission +* Other unethical or unprofessional conduct + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +By adopting this Code of Conduct, project maintainers commit themselves to fairly and consistently applying these principles to every aspect of managing this project. Project maintainers who do not follow or enforce the Code of Conduct may be permanently removed from the project team. + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project maintainer at sebastian@phpunit.de. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. Maintainers are obligated to maintain confidentiality with regard to the reporter of an incident. + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.3.0, available at [https://contributor-covenant.org/version/1/3/0/][version] + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/3/0/ diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 00000000000..24f5ca5019e --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1,136 @@ +# Contributing to PHPUnit + +## Welcome! + +We look forward to your contributions! Here are some examples how you can contribute: + +* [Report a bug](https://github.com/sebastianbergmann/phpunit/issues/new?labels=type/bug&template=BUG.md) +* [Propose a new feature](https://github.com/sebastianbergmann/phpunit/issues/new?labels=type/enhancement&template=FEATURE_REQUEST.md) +* [Send a pull request](https://github.com/sebastianbergmann/phpunit/pulls) + + +## We have a Code of Conduct + +Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms. + + +## Any contributions you make will be under the BSD-3-Clause License + +When you submit code changes, your submissions are understood to be under the same [BSD-3-Clause License](https://github.com/sebastianbergmann/phpunit/blob/main/LICENSE) that covers the project. By contributing to this project, you agree that your contributions will be licensed under its BSD-3-Clause License. + +### Do Not Violate Copyright + +Only submit a pull request with your own original code. Do NOT submit a pull request containing code which you have largely copied from +another project, unless you wrote the respective code yourself. + +Open Source does not mean that copyright does not apply. Copyright infringements will not be tolerated and can lead to you being banned from this project and repository. + +### Do Not Submit AI-Generated Pull Requests + +The same goes for (largely) AI-generated pull requests. These are not welcome as they will be based on copyrighted code from others +without accreditation and without taking the license of the original code into account, let alone getting permission +for the use of the code or for re-licensing. + +Aside from that, the experience is that AI-generated pull requests will be incorrect 100% of the time and cost reviewers too much time. +Submitting a (largely) AI-generated pull request will lead to you being banned from this project and repository. + +## Write bug reports with detail, background, and sample code + +[This is an example](https://github.com/sebastianbergmann/phpunit/issues/4376) of a bug report I wrote, and I think it's not too bad. + +In your bug report, please provide the following: + +* A quick summary and/or background +* Steps to reproduce + * Be specific! + * Give sample code if you can. +* What you expected would happen +* What actually happens +* Notes (possibly including why you think this might be happening, or stuff you tried that didn't work) + +Please do not report a bug for a [version of PHPUnit that is no longer supported](https://phpunit.de/supported-versions.html). Please do not report a bug if you are using a [version of PHP that is not supported by the version of PHPUnit](https://phpunit.de/supported-versions.html) you are using. + +Please do not report an issue if you are not using PHPUnit directly, but rather a third-party wrapper around it. + +Please do not report an issue if you are using a third-party extension such as alternative output printers. + +Please post code and output as text ([using proper markup](https://guides.github.com/features/mastering-markdown/)). Do not post screenshots of code or output. + +Please include the output of `composer info | sort` if you installed PHPUnit using Composer. + +Please use the most specific issue tracker to search for existing tickets and to open new tickets: + +* [General problems](https://github.com/sebastianbergmann/phpunit/issues) +* [Code Coverage](https://github.com/sebastianbergmann/php-code-coverage/issues) +* [Documentation](https://github.com/sebastianbergmann/phpunit-documentation-english/issues) +* [Website](https://github.com/sebastianbergmann/phpunit-website/issues) + + +## Workflow for Pull Requests + +1. Fork the repository. +2. Create your branch from `main` if you plan to implement new functionality or change existing code significantly; create your branch from the oldest branch that is affected by the bug if you plan to fix a bug. +3. Implement your change and add tests for it. +4. Ensure the test suite passes. +5. Ensure the code complies with our coding guidelines (see below). +6. Send that pull request! + +Please make sure you have [set up your username and email address](https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup) for use with Git. Strings such as `silly nick name ` look really stupid in the commit history of a project. + +We encourage you to [sign your Git commits with your GPG key](https://docs.github.com/en/github/authenticating-to-github/signing-commits). + +Pull requests for bug fixes must be made for the oldest branch that is [supported](https://phpunit.de/supported-versions.html). Pull requests for new features must be based on the `main` branch. + +We are trying to keep backwards compatibility breaks in PHPUnit to an absolute minimum. Please take this into account when proposing changes. + +Due to time constraints, we are not always able to respond as quickly as we would like. Please do not take delays personal and feel free to remind us if you feel that we forgot to respond. + + +## Coding Guidelines + +This project comes with a configuration file (located at `/.php-cs-fixer.dist.php` in the repository) and an executable for [php-cs-fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) (located at `/tools/php-cs-fixer` in the repository) that you can use to (re)format your source code for compliance with this project's coding guidelines: + +```bash +$ ./tools/php-cs-fixer fix +``` + +Please understand that we will not accept a pull request when its changes violate this project's coding guidelines. + +## Static Analysis + +This project comes with a configuration file (located at `/phpstan.neon` in the repository) and an executable for [PHPStan](https://phpstan.org/) (located at `/tools/phpstan` in the repository) that you can use to perform static analysis: + +```bash +$ ./tools/phpstan +``` + +## Using PHPUnit from a Git checkout + +The following commands can be used to perform the initial checkout of PHPUnit: + +```bash +$ git clone git://github.com/sebastianbergmann/phpunit.git + +$ cd phpunit +``` + +Install PHPUnit's dependencies using [Composer](https://getcomposer.org/): + +```bash +$ ./tools/composer install +``` + +The `phpunit` script can be used to invoke the PHPUnit test runner: + +```bash +$ ./phpunit --version +``` + + +## Running PHPUnit's own test suite + +After following the steps shown above, PHPUnit's own test suite is run like this: + +```bash +$ ./phpunit +``` diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..292fadb829f --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,5 @@ +github: sebastianbergmann +liberapay: sebastianbergmann +thanks_dev: u/gh/sebastianbergmann +tidelift: "packagist/phpunit/phpunit" +custom: https://phpunit.de/sponsors.html diff --git a/.github/ISSUE_TEMPLATE/1_BUG.md b/.github/ISSUE_TEMPLATE/1_BUG.md new file mode 100644 index 00000000000..581c291213a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/1_BUG.md @@ -0,0 +1,41 @@ +--- +name: 🐞 Bug Report +about: Something is broken? +labels: type/bug +--- + + + +| Q | A +| --------------------| --------------- +| PHPUnit version | x.y.z +| PHP version | x.y.z +| Installation Method | Composer / PHAR + +#### Summary + + + +#### Current behavior + + + +#### How to reproduce + + + +#### Expected behavior + + diff --git a/.github/ISSUE_TEMPLATE/2_COMPATIBILITY.md b/.github/ISSUE_TEMPLATE/2_COMPATIBILITY.md new file mode 100644 index 00000000000..f3573a1bc7a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/2_COMPATIBILITY.md @@ -0,0 +1,39 @@ +--- +name: ⚠️ PHP Compatibility Issue +about: A change in PHP requires adaption in PHPUnit? +labels: type/change-in-php-requires-adaptation +--- + + + +| Q | A +| --------------------| --------------- +| PHPUnit version | x.y.z +| PHP version | x.y.z +| Installation Method | Composer / PHAR + +#### Summary + + + +#### Current behavior + + + +#### How to reproduce + + + +#### Expected behavior + + diff --git a/.github/ISSUE_TEMPLATE/3_FEATURE_REQUEST.md b/.github/ISSUE_TEMPLATE/3_FEATURE_REQUEST.md new file mode 100644 index 00000000000..262e52e085d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/3_FEATURE_REQUEST.md @@ -0,0 +1,7 @@ +--- +name: 🎉 Feature Request +about: You have a neat idea that should be implemented? +labels: type/enhancement +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE/FAILING_TEST.md b/.github/PULL_REQUEST_TEMPLATE/FAILING_TEST.md new file mode 100644 index 00000000000..e729f28c4f7 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/FAILING_TEST.md @@ -0,0 +1,10 @@ +--- +name: 🐞 Failing Test +about: You found a bug and have a failing test? +labels: type/bug, type/tests +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE/FIX.md b/.github/PULL_REQUEST_TEMPLATE/FIX.md new file mode 100644 index 00000000000..3f838b6f88b --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/FIX.md @@ -0,0 +1,10 @@ +--- +name: 🐞 Bug Fix +about: You have a fix for a bug? +labels: type/bug +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE/IMPROVEMENT.md b/.github/PULL_REQUEST_TEMPLATE/IMPROVEMENT.md new file mode 100644 index 00000000000..80ac18492aa --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/IMPROVEMENT.md @@ -0,0 +1,9 @@ +--- +name: ⚙ Improvement +about: You have some improvement to make PHPUnit better? +labels: type/enhancement +--- + + diff --git a/.github/PULL_REQUEST_TEMPLATE/NEW_FEATURE.md b/.github/PULL_REQUEST_TEMPLATE/NEW_FEATURE.md new file mode 100644 index 00000000000..108bb29f002 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE/NEW_FEATURE.md @@ -0,0 +1,9 @@ +--- +name: 🎉 New Feature +about: You have implemented some neat idea that you want to make part of PHPUnit? +labels: type/enhancement +--- + + diff --git a/.github/img/bubble-shooter.png b/.github/img/bubble-shooter.png new file mode 100755 index 00000000000..f358c1c1ed0 Binary files /dev/null and b/.github/img/bubble-shooter.png differ diff --git a/.github/img/in2it.svg b/.github/img/in2it.svg new file mode 100644 index 00000000000..a58fb6f6d58 --- /dev/null +++ b/.github/img/in2it.svg @@ -0,0 +1,39 @@ + + + + + Produced by OmniGraffle 7.18.2\n2021-01-25 13:37:49 +0000 + + In2it Logo White SVG + + Layer 1 + + + + + + 2 + + + + in + + + + + + + + + it + + + + + + + + + + + diff --git a/.github/img/lambdatest.svg b/.github/img/lambdatest.svg new file mode 100644 index 00000000000..f49a7948563 --- /dev/null +++ b/.github/img/lambdatest.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/.github/img/phpunit.svg b/.github/img/phpunit.svg new file mode 100755 index 00000000000..8fe04bd143c --- /dev/null +++ b/.github/img/phpunit.svg @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/img/testmo.svg b/.github/img/testmo.svg new file mode 100644 index 00000000000..791908c2977 --- /dev/null +++ b/.github/img/testmo.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/img/tideways.svg b/.github/img/tideways.svg new file mode 100644 index 00000000000..74b6b993cd4 --- /dev/null +++ b/.github/img/tideways.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.github/img/typo3.svg b/.github/img/typo3.svg new file mode 100644 index 00000000000..3ceb2f2ecaf --- /dev/null +++ b/.github/img/typo3.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/.github/img/vema.svg b/.github/img/vema.svg new file mode 100644 index 00000000000..4555ab42774 --- /dev/null +++ b/.github/img/vema.svg @@ -0,0 +1,18 @@ + + + + + + + + + diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 00000000000..698ad13f521 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,478 @@ +# https://docs.github.com/en/actions + +on: + pull_request: null + push: null + +name: CI + +env: + COMPOSER_ROOT_VERSION: "13.0.x-dev" + PHP_VERSION: 8.4 + +permissions: + contents: read + +jobs: + dependency-validation: + name: Dependency Validation + + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + extensions: none, ctype, curl, dom, json, libxml, mbstring, openssl, phar, tokenizer, xml, xmlwriter, pcntl + coverage: none + tools: none + + - name: Ensure that composer.json is valid + run: ./tools/composer validate --no-ansi --strict composer.json + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Ensure that dependencies can be installed + run: ./tools/composer install --no-ansi --dry-run + + coding-guidelines: + name: Coding Guidelines + + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + extensions: none, iconv, json, phar, tokenizer + coverage: none + tools: none + + - name: Run PHP-CS-Fixer + run: ./tools/php-cs-fixer check --show-progress=dots --using-cache=no --verbose + + static-analysis: + name: Static Analysis + + needs: + - dependency-validation + + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + coverage: none + tools: none + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies with Composer + run: ./tools/composer install --no-interaction --no-ansi --no-progress + + - name: Run PHPStan + run: ./tools/phpstan analyse --no-progress --error-format=github + + unit-tests: + name: Unit Tests + + needs: + - dependency-validation + + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + + env: + PHP_EXTENSIONS: none, ctype, curl, dom, json, libxml, mbstring, openssl, phar, tokenizer, xml, xmlwriter, pcntl + PHP_INI_VALUES: memory_limit=-1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + + php-version: + - "8.4" + - "8.5" + - "8.6" + + steps: + - name: Configure Git to avoid issues with line endings + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf false + + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: ${{ env.PHP_EXTENSIONS }} + ini-values: ${{ env.PHP_INI_VALUES }} + tools: none + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies with Composer + run: php ./tools/composer install --no-ansi --no-interaction --no-progress + + - name: Run tests with PHPUnit + run: php ./phpunit --testsuite unit --order-by depends,random --display-all-issues + + end-to-end-tests: + name: End-to-End Tests + + needs: + - unit-tests + + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + + env: + PHP_EXTENSIONS: none, ctype, curl, dom, json, libxml, mbstring, openssl, pdo, phar, tokenizer, xml, xmlwriter, pcntl + PHP_INI_VALUES: zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + + php-version: + - "8.4" + - "8.5" + - "8.6" + + steps: + - name: Configure Git to avoid issues with line endings + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf false + + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: ${{ env.PHP_EXTENSIONS }} + ini-values: ${{ env.PHP_INI_VALUES }} + tools: none + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies with Composer + run: php ./tools/composer install --no-ansi --no-interaction --no-progress + + - name: Run tests with PHPUnit + run: php ./phpunit --testsuite end-to-end --order-by depends,random --display-all-issues + + code-coverage: + name: Code Coverage + + needs: + - end-to-end-tests + + runs-on: ubuntu-latest + timeout-minutes: 10 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + coverage: xdebug + extensions: none, ctype, curl, dom, json, libxml, mbstring, pdo, phar, tokenizer, xml, xmlwriter, pcntl + ini-values: zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + tools: none + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies with Composer + run: ./tools/composer install --no-ansi --no-interaction --no-progress + + - name: Collect code coverage with PHPUnit + run: ./phpunit --log-junit test-results.xml --coverage-openclover=code-coverage.xml + + - name: Upload test results to Codecov.io + if: ${{ !cancelled() }} + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + report_type: test_results + disable_search: true + files: ./test-results.xml + + - name: Upload code coverage data to Codecov.io + if: ${{ !cancelled() }} + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + report_type: coverage + disable_search: true + files: ./code-coverage.xml + + build-phar: + name: Build PHAR + + needs: + - end-to-end-tests + + runs-on: ubuntu-latest + timeout-minutes: 10 + + env: + PHP_EXTENSIONS: none, ctype, dom, json, fileinfo, iconv, libxml, mbstring, phar, tokenizer, xml, xmlwriter, pcntl + PHP_INI_VALUES: phar.readonly=0, zend.assertions=1 + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ env.PHP_VERSION }} + coverage: none + extensions: ${{ env.PHP_EXTENSIONS }} + ini-values: ${{ env.PHP_INI_VALUES }} + tools: none + + - name: Install java + uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: 11 + + - name: Build PHAR + run: ant phar-snapshot + + - name: Upload PHAR + uses: actions/upload-artifact@v6 + with: + name: phpunit-snapshot-phar + overwrite: true + path: ./build/artifacts/phpunit-snapshot.phar + retention-days: 7 + + test-phar: + name: Test PHAR + + needs: + - build-phar + + runs-on: ubuntu-latest + timeout-minutes: 10 + + env: + PHP_EXTENSIONS: none, ctype, curl, dom, json, fileinfo, iconv, libxml, mbstring, phar, tokenizer, xml, xmlwriter, pcntl + PHP_INI_VALUES: phar.readonly=0, zend.assertions=1 + + strategy: + fail-fast: false + matrix: + php-version: + - "8.4" + - "8.5" + - "8.6" + + coverage: + - pcov + - xdebug + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 1 + ref: ${{ github.event.pull_request.head.sha || github.sha }} + + - name: Use local branch + shell: bash + run: | + BRANCH=$([ "${{ github.event_name }}" == "pull_request" ] && echo "${{ github.head_ref }}" || echo "${{ github.ref_name }}") + git branch -D $BRANCH 2>/dev/null || true + git branch $BRANCH HEAD + git checkout $BRANCH + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: ${{ matrix.coverage }} + extensions: ${{ env.PHP_EXTENSIONS }} + ini-values: ${{ env.PHP_INI_VALUES }} + tools: none + + - name: Install java + uses: actions/setup-java@v5 + with: + distribution: zulu + java-version: 11 + + - name: Download PHAR + uses: actions/download-artifact@v7 + with: + name: phpunit-snapshot-phar + path: ./build/artifacts/ + + - name: Make PHAR executable + run: chmod +x ./build/artifacts/phpunit-snapshot.phar + + - name: Run PHAR-specific tests + run: ant run-phar-specific-tests diff --git a/.github/workflows/nightly.yaml b/.github/workflows/nightly.yaml new file mode 100644 index 00000000000..3190d55adeb --- /dev/null +++ b/.github/workflows/nightly.yaml @@ -0,0 +1,143 @@ +# https://docs.github.com/en/actions + +on: + schedule: + - cron: "15 0 * * *" + workflow_dispatch: ~ + +name: Nightly + +permissions: + contents: read + +jobs: + run-tests: + name: Tests + + runs-on: ${{ matrix.os }} + timeout-minutes: 10 + + env: + PHP_EXTENSIONS: none, ctype, curl, dom, json, libxml, mbstring, openssl, pdo, phar, tokenizer, xml, xmlwriter + PHP_INI_VALUES: memory_limit=-1, zend.assertions=1, error_reporting=-1, log_errors_max_len=0, display_errors=On + + strategy: + fail-fast: false + matrix: + os: + - ubuntu-latest + - windows-latest + + phpunit-branch: + - main + - 12.5 + - 11.5 + - 10.5 + - 9.6 + - 8.5 + + php-version: + - 7.2 + - 7.3 + - 7.4 + - 8.0 + - 8.1 + - 8.2 + - 8.3 + - 8.4 + - 8.5 + - 8.6 + + exclude: + - phpunit-branch: 8.5 + php-version: 7.2 + - phpunit-branch: 8.5 + php-version: 7.3 + - phpunit-branch: 9.6 + php-version: 7.2 + - phpunit-branch: 9.6 + php-version: 7.3 + - phpunit-branch: 10.5 + php-version: 7.2 + - phpunit-branch: 10.5 + php-version: 7.3 + - phpunit-branch: 10.5 + php-version: 7.4 + - phpunit-branch: 10.5 + php-version: 8.0 + - phpunit-branch: 11.5 + php-version: 7.2 + - phpunit-branch: 11.5 + php-version: 7.3 + - phpunit-branch: 11.5 + php-version: 7.4 + - phpunit-branch: 11.5 + php-version: 8.0 + - phpunit-branch: 11.5 + php-version: 8.1 + - phpunit-branch: 12.5 + php-version: 7.2 + - phpunit-branch: 12.5 + php-version: 7.3 + - phpunit-branch: 12.5 + php-version: 7.4 + - phpunit-branch: 12.5 + php-version: 8.0 + - phpunit-branch: 12.5 + php-version: 8.1 + - phpunit-branch: 12.5 + php-version: 8.2 + - phpunit-branch: main + php-version: 7.2 + - phpunit-branch: main + php-version: 7.3 + - phpunit-branch: main + php-version: 7.4 + - phpunit-branch: main + php-version: 8.0 + - phpunit-branch: main + php-version: 8.1 + - phpunit-branch: main + php-version: 8.2 + - phpunit-branch: main + php-version: 8.3 + + steps: + - name: Configure Git to avoid issues with line endings + if: matrix.os == 'windows-latest' + run: git config --global core.autocrlf false + + - name: Checkout + uses: actions/checkout@v6 + with: + ref: ${{ matrix.phpunit-branch }} + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + extensions: ${{ env.PHP_EXTENSIONS }} + ini-values: ${{ env.PHP_INI_VALUES }} + tools: none + + - name: Get Composer cache directory + id: composer-cache + shell: bash + run: | + echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT" + + - name: Cache Composer cache directory + uses: actions/cache@v5 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Install dependencies with Composer + run: php ./tools/composer install --no-ansi --no-interaction --no-progress + + - name: Run unit tests with PHPUnit + run: php ./phpunit --testsuite unit --order-by depends,random + + - name: Run end-to-end tests with PHPUnit + run: php ./phpunit --testsuite end-to-end --order-by depends,random diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000000..b3ce97d19a2 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,54 @@ +# https://docs.github.com/en/actions + +on: + push: + tags: + - "**" + +name: Release + +jobs: + release: + name: Release + + runs-on: ubuntu-latest + timeout-minutes: 10 + + permissions: + contents: write + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: 8.4 + coverage: none + extensions: none + tools: none + + - name: Determine tag + run: echo "RELEASE_TAG=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + - name: Parse ChangeLog + run: build/scripts/extract-release-notes.php ${{ env.RELEASE_TAG }} > release-notes.md + + - name: Create release + uses: ncipollo/release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ env.RELEASE_TAG }} + name: PHPUnit ${{ env.RELEASE_TAG }} + bodyFile: release-notes.md + commit: "13.0" + + - name: Announce release + id: mastodon + uses: cbrgm/mastodon-github-action@v2 + with: + access-token: ${{ secrets.MASTODON_ACCESS_TOKEN }} + url: ${{ secrets.MASTODON_URL }} + language: "en" + message: "#PHPUnit ${{ env.RELEASE_TAG }} has been released: https://github.com/sebastianbergmann/phpunit/releases/tag/${{ env.RELEASE_TAG }}" diff --git a/.gitignore b/.gitignore index c9cf08f6b14..02631f2b73d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,28 @@ -build/api -build/code-browser -build/coverage -build/logs -build/pdepend -build/phar -build/phpdox -build/*.phar -Tests/TextUI/*.diff -Tests/TextUI/*.exp -Tests/TextUI/*.log -Tests/TextUI/*.out -Tests/TextUI/*.php -phpunit.xml -cache.properties -.idea +# PhpStorm +/.idea + +# Composer +/vendor + +# Apache Ant +/.ant_targets + +# Build artifacts and temporary files +/build/artifacts +/build/tmp +/tests/autoload.php + +# PHP-CS-Fixer +/.php-cs-fixer.php +/.php-cs-fixer.cache + +# PHPUnit +/.phpunit.cache +.phpunit.result.cache + +# Temporary files generated by PHPT test runner +/tests/end-to-end/*.diff +/tests/end-to-end/*.exp +/tests/end-to-end/*.log +/tests/end-to-end/*.out +/tests/end-to-end/*.php diff --git a/.phive/phars.xml b/.phive/phars.xml new file mode 100644 index 00000000000..c93e395e14a --- /dev/null +++ b/.phive/phars.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 00000000000..38093bb0847 --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,380 @@ + + +For the full copyright and license information, please view the LICENSE +file that was distributed with this source code. +EOF; + +$finder = PhpCsFixer\Finder::create() + ->files() + ->in(__DIR__ . '/src') + ->in(__DIR__ . '/tests/_files') + ->in(__DIR__ . '/tests/end-to-end') + ->in(__DIR__ . '/tests/unit') + // DeprecatedPhpFeatureTest.php must not use declare(strict_types=1); + ->notName('DeprecatedPhpFeatureTest.php') + // UseBaselineTest.php must not use declare(strict_types=1); + ->notName('UseBaselineTest.php') + // Issue5795Test.php contains required whitespace that would be cleaned up + ->notName('Issue5795Test.php') + // Hook methods that should be protected must be public in TestAttributeOnHookMethodsTest.php + ->notName('TestAttributeOnHookMethodsTest.php') + // InvokableConstraintAndPipeOperatorTest.php uses PHP 8.5 syntax + ->notName('InvokableConstraintAndPipeOperatorTest.php') + ->notName('*.phpt'); + +$config = new PhpCsFixer\Config; +$config->setFinder($finder) + ->setRiskyAllowed(true) + ->setRules([ + 'align_multiline_comment' => true, + 'array_indentation' => true, + 'array_push' => true, + 'array_syntax' => ['syntax' => 'short'], + 'attribute_empty_parentheses' => [ + 'use_parentheses' => false, + ], + 'backtick_to_shell_exec' => true, + 'binary_operator_spaces' => [ + 'operators' => [ + '*=' => 'align_single_space_minimal', + '+=' => 'align_single_space_minimal', + '-=' => 'align_single_space_minimal', + '/=' => 'align_single_space_minimal', + '=' => 'align_single_space_minimal', + '=>' => 'align_single_space_minimal', + ], + ], + 'blank_line_after_namespace' => true, + 'blank_line_before_statement' => [ + 'statements' => [ + 'break', + 'case', + 'continue', + 'declare', + 'default', + 'do', + 'exit', + 'for', + 'foreach', + 'goto', + 'if', + 'include', + 'include_once', + 'phpdoc', + 'require', + 'require_once', + 'return', + 'switch', + 'throw', + 'try', + 'while', + 'yield', + 'yield_from', + ], + ], + 'blank_lines_before_namespace' => [ + 'max_line_breaks' => 1, + 'min_line_breaks' => 0, + ], + 'braces_position' => [ + 'anonymous_classes_opening_brace' => 'next_line_unless_newline_at_signature_end', + 'anonymous_functions_opening_brace' => 'next_line_unless_newline_at_signature_end', + ], + 'cast_spaces' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'const' => 'none', + 'method' => 'one', + 'property' => 'only_if_meta' + ] + ], + 'class_definition' => true, + 'clean_namespace' => true, + 'combine_consecutive_issets' => true, + 'combine_consecutive_unsets' => true, + 'combine_nested_dirname' => true, + 'compact_nullable_type_declaration' => true, + 'concat_space' => ['spacing' => 'one'], + 'constant_case' => true, + 'control_structure_braces' => true, + 'control_structure_continuation_position' => true, + 'declare_equal_normalize' => ['space' => 'none'], + 'declare_parentheses' => true, + 'declare_strict_types' => true, + 'dir_constant' => true, + 'echo_tag_syntax' => true, + 'elseif' => true, + 'encoding' => true, + 'ereg_to_preg' => true, + 'explicit_indirect_variable' => true, + 'explicit_string_variable' => true, + 'fopen_flag_order' => true, + 'full_opening_tag' => true, + 'fully_qualified_strict_types' => ['import_symbols' => true], + 'function_declaration' => true, + 'function_to_constant' => true, + 'get_class_to_class_keyword' => true, + 'global_namespace_import' => [ + 'import_classes' => true, + 'import_constants' => true, + 'import_functions' => true, + ], + 'header_comment' => ['header' => $header, 'separate' => 'none'], + 'heredoc_to_nowdoc' => true, + 'implode_call' => true, + 'include' => true, + 'increment_style' => [ + 'style' => 'post', + ], + 'indentation_type' => true, + 'integer_literal_case' => true, + 'is_null' => true, + 'lambda_not_used_import' => true, + 'line_ending' => true, + 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, + 'lowercase_cast' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'magic_method_casing' => true, + 'method_argument_space' => [ + 'on_multiline' => 'ensure_fully_multiline', + ], + 'method_chaining_indentation' => true, + 'modernize_strpos' => true, + 'modernize_types_casting' => true, + 'multiline_comment_opening_closing' => true, + 'multiline_whitespace_before_semicolons' => true, + 'native_constant_invocation' => true, + 'native_function_casing' => false, + 'native_function_invocation' => [ + 'include' => [ + '@internal', + ], + ], + 'native_type_declaration_casing' => true, + 'new_expression_parentheses' => true, + 'new_with_parentheses' => [ + 'anonymous_class' => false, + 'named_class' => false, + ], + 'no_alias_functions' => true, + 'no_alias_language_construct_call' => true, + 'no_alternative_syntax' => true, + 'no_binary_string' => true, + 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => true, + 'no_break_comment' => true, + 'no_closing_tag' => true, + 'no_empty_comment' => true, + 'no_empty_phpdoc' => true, + 'no_empty_statement' => true, + 'no_extra_blank_lines' => [ + 'tokens' => [ + 'attribute', + 'break', + 'case', + 'continue', + 'curly_brace_block', + 'default', + 'extra', + 'parenthesis_brace_block', + 'return', + 'square_brace_block', + 'switch', + 'throw', + 'use', + ], + ], + 'no_homoglyph_names' => true, + 'no_leading_import_slash' => true, + 'no_leading_namespace_whitespace' => true, + 'no_mixed_echo_print' => ['use' => 'print'], + 'no_multiline_whitespace_around_double_arrow' => true, + 'no_multiple_statements_per_line' => true, + 'no_null_property_initialization' => true, + 'no_php4_constructor' => true, + 'no_short_bool_cast' => true, + 'no_singleline_whitespace_before_semicolons' => true, + 'no_space_around_double_colon' => true, + 'no_spaces_after_function_name' => true, + 'no_spaces_around_offset' => true, + 'no_superfluous_elseif' => true, + 'no_superfluous_phpdoc_tags' => [ + 'allow_mixed' => true, + ], + 'no_trailing_comma_in_singleline' => true, + 'no_trailing_whitespace' => true, + 'no_trailing_whitespace_in_comment' => true, + 'no_trailing_whitespace_in_string' => true, + 'no_unneeded_braces' => true, + 'no_unneeded_control_parentheses' => true, + 'no_unneeded_final_method' => true, + 'no_unneeded_import_alias' => true, + 'no_unreachable_default_argument_value' => true, + 'no_unset_cast' => true, + 'no_unset_on_property' => true, + 'no_unused_imports' => true, + 'no_useless_concat_operator' => true, + 'no_useless_else' => true, + 'no_useless_nullsafe_operator' => true, + 'no_useless_return' => true, + 'no_useless_sprintf' => true, + 'no_whitespace_before_comma_in_array' => true, + 'no_whitespace_in_blank_line' => true, + 'non_printable_character' => true, + 'normalize_index_brace' => true, + 'nullable_type_declaration_for_default_null_value' => true, + 'object_operator_without_whitespace' => true, + 'octal_notation' => true, + 'operator_linebreak' => [ + 'only_booleans' => true, + 'position' => 'end', + ], + 'ordered_class_elements' => [ + 'order' => [ + 'use_trait', + 'constant_public', + 'constant_protected', + 'constant_private', + 'property_public_static', + 'property_protected_static', + 'property_private_static', + 'property_public', + 'property_protected', + 'property_private', + 'method_public_static', + 'construct', + 'destruct', + 'magic', + 'phpunit', + 'method_public', + 'method_protected', + 'method_private', + 'method_protected_static', + 'method_private_static', + ], + ], + 'ordered_imports' => [ + 'imports_order' => [ + 'const', + 'function', + 'class', + ] + ], + 'ordered_interfaces' => [ + 'direction' => 'ascend', + 'order' => 'alpha', + ], + 'ordered_traits' => true, + 'ordered_types' => true, + 'php_unit_set_up_tear_down_visibility' => true, + 'php_unit_test_case_static_method_calls' => [ + 'call_type' => 'this', + ], + 'phpdoc_add_missing_param_annotation' => false, + 'phpdoc_align' => true, + 'phpdoc_annotation_without_dot' => true, + 'phpdoc_indent' => true, + 'phpdoc_inline_tag_normalizer' => true, + 'phpdoc_no_access' => true, + 'phpdoc_no_alias_tag' => true, + 'phpdoc_no_empty_return' => true, + 'phpdoc_no_package' => true, + 'phpdoc_no_useless_inheritdoc' => true, + 'phpdoc_order' => true, + 'phpdoc_order_by_value' => [ + 'annotations' => [ + 'covers', + 'dataProvider', + 'throws', + 'uses', + ], + ], + 'phpdoc_param_order' => true, + 'phpdoc_return_self_reference' => true, + 'phpdoc_scalar' => true, + 'phpdoc_separation' => true, + 'phpdoc_single_line_var_spacing' => true, + 'phpdoc_summary' => true, + 'phpdoc_tag_casing' => true, + 'phpdoc_tag_type' => true, + 'phpdoc_to_comment' => false, + 'phpdoc_trim' => true, + 'phpdoc_trim_consecutive_blank_line_separation' => true, + 'phpdoc_types' => ['groups' => ['simple', 'meta']], + 'phpdoc_types_order' => true, + 'phpdoc_var_annotation_correct_order' => true, + 'phpdoc_var_without_name' => true, + 'pow_to_exponentiation' => true, + 'protected_to_private' => true, + 'return_assignment' => true, + 'return_type_declaration' => ['space_before' => 'none'], + 'self_accessor' => true, + 'self_static_accessor' => true, + 'semicolon_after_instruction' => true, + 'set_type_to_cast' => true, + 'short_scalar_cast' => true, + 'simple_to_complex_string_variable' => true, + 'simplified_null_return' => false, + 'single_blank_line_at_eof' => true, + 'single_class_element_per_statement' => true, + 'single_import_per_statement' => true, + 'single_line_after_imports' => true, + 'single_line_comment_spacing' => true, + 'single_quote' => true, + 'single_space_around_construct' => true, + 'single_trait_insert_per_statement' => true, + 'space_after_semicolon' => true, + 'spaces_inside_parentheses' => [ + 'space' => 'none', + ], + 'standardize_increment' => true, + 'standardize_not_equals' => true, + 'statement_indentation' => true, + 'static_lambda' => true, + 'strict_param' => true, + 'string_length_to_empty'=> true, + 'string_line_ending' => true, + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'switch_continue_to_break' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_elvis_operator' => true, + 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline' => [ + 'elements' => [ + 'arguments', + 'arrays', + 'match', + ] + ], + 'trim_array_spaces' => true, + 'type_declaration_spaces' => [ + 'elements' => [ + 'function', + ], + ], + 'types_spaces' => true, + 'unary_operator_spaces' => true, + 'modifier_keywords' => [ + 'elements' => [ + 'const', + 'method', + 'property', + ], + ], + 'void_return' => true, + 'whitespace_after_comma_in_array' => true, + ]); + +$config->setCacheFile(__DIR__ . '/.php-cs-fixer.cache/' . json_decode((string) @file_get_contents('composer.json'), true)["extra"]["branch-alias"]["dev-main"] ?? 'unknown'); + +$config->setParallelConfig(\PhpCsFixer\Runner\Parallel\ParallelConfigFactory::detect()); + +return $config; diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5c538e75105..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: php - -php: - - 5.4 - -env: - - INSTALL_PHP_INVOKER=0 - - INSTALL_PHP_INVOKER=1 - -before_script: - - sh -c "if [ '$INSTALL_PHP_INVOKER' = '1' ]; then composer require --dev --prefer-source phpunit/php-invoker:\>=1.2.0; else composer install --dev --prefer-source; fi" - -script: ./phpunit.php --configuration ./build/travis-ci.xml - -notifications: - email: false - irc: - channels: - - "irc.freenode.org#phpunit" - use_notice: true diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index 9275ee65812..00000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,28 +0,0 @@ -Contributing to PHPUnit -======================= - -Contributions to PHPUnit, its related modules, and its documentation are always welcome. You make our lives easier by sending us your contributions through GitHub pull requests. - -Please note that the `3.7` branch is closed for features and that pull requests should to be based on `master` or the `3.8` branch once it exists. - -We are trying to keep backwards compatibility breaks in PHPUnit 3.8 to an absolute minimum, so please take this into account when proposing changes. - -Due to time constraints, we are not always able to respond as quickly as we would like. Please do not take delays personal and feel free to remind us here or on IRC if you feel that we forgot to respond. - -Using PHPUnit From a Git Checkout ---------------------------------- - -The following commands can be used to perform the initial checkout of PHPUnit: - - git clone git://github.com/sebastianbergmann/phpunit.git - cd phpunit - -To retrieve PHPUnit's dependencies, you can use [Composer](http://getcomposer.org/download/). If you do not have Composer installed, you can download the latest PHAR with the following command: - - curl -O http://getcomposer.org/composer.phar - -Once Composer is installed, you can fetch PHPUnit's dependencies with the following command: - - php composer.phar install --dev - -The `phpunit.php` script can be used to invoke the PHPUnit test runner. diff --git a/ChangeLog-13.0.md b/ChangeLog-13.0.md new file mode 100644 index 00000000000..db4530bcd60 --- /dev/null +++ b/ChangeLog-13.0.md @@ -0,0 +1,24 @@ +# Changes in PHPUnit 13.0 + +All notable changes of the PHPUnit 13.0 release series are documented in this file using the [Keep a CHANGELOG](https://keepachangelog.com/) principles. + +## [13.0.0] - 2026-02-06 + +### Added + +* [#6450](https://github.com/sebastianbergmann/phpunit/issues/6450): `TestCase::invokeTestMethod()` method for customizing test method invocation + +### Removed + +* [#6054](https://github.com/sebastianbergmann/phpunit/issues/6054): `Assert::isType()` +* [#6057](https://github.com/sebastianbergmann/phpunit/issues/6057): `assertContainsOnly()` and `assertNotContainsOnly()` +* [#6061](https://github.com/sebastianbergmann/phpunit/issues/6061): `containsOnly()` +* [#6076](https://github.com/sebastianbergmann/phpunit/issues/6076): Support for PHP 8.3 +* [#6141](https://github.com/sebastianbergmann/phpunit/issues/6141): `testClassName()` method on event value objects for hook methods called for test methods +* [#6230](https://github.com/sebastianbergmann/phpunit/issues/6230): `Configuration::includeTestSuite()` and `Configuration::excludeTestSuite()` +* [#6241](https://github.com/sebastianbergmann/phpunit/issues/6241): `--dont-report-useless-tests` CLI option +* [#6247](https://github.com/sebastianbergmann/phpunit/issues/6247): Support for using `#[CoversNothing]` on a test method +* [#6285](https://github.com/sebastianbergmann/phpunit/issues/6285): `#[RunClassInSeparateProcess]` attribute +* [#6356](https://github.com/sebastianbergmann/phpunit/issues/6356): Support for version constraint string argument without explicit version comparison operator + +[13.0.0]: https://github.com/sebastianbergmann/phpunit/compare/12.5...main diff --git a/ChangeLog.md b/ChangeLog.md deleted file mode 100644 index 55a670541d2..00000000000 --- a/ChangeLog.md +++ /dev/null @@ -1,27 +0,0 @@ -PHPUnit 3.8 -=========== - -This is the list of changes for the PHPUnit 3.8 release series. - -PHPUnit 3.8.0 -------------- - -* Implemented #859: Added PHP label validation to attribute assertions. -* Implemented #838: Added a base test listener. -* Implemented #835: Printers that extend `PHPUnit_TextUI_ResultPrinter` should have similar construction -* Implemented #834: Added the `@requires OS` annotation. -* Implemented #773: Recursive and repeated arrays are more gracefully when comparison differences are exported. -* Implemented #758: Show a proper stack trace when @expectedException fails due to a unexcepted exception being thrown. -* Implemented #746: Allow identity checking for non-object types in all asserts that depend on `TraversableContains`. -* Implemented #711: `coverage-text` now has an XML `showOnlySummary` option. -* Implemented #719: The `--stderr` flag now respects `--colors` and `--debug`. -* Implemented #382: Added the `$options` parameter to `PHPUnit_Framework_TestCase::getMockFromWsdl()` for configuring the `SoapClient`. -* A test will now fail in strict mode when it uses the `@covers` annotation and code that is not expected to be covered is executed. -* Fixed #240: XML strings are escaped by removing invalid characters. -* Fixed #261: `setUp()` and `setUpBeforeClass()` are run before filters are applied. -* Fixed #541: Excluded groups are counted towards total number of tests being executed. -* Fixed #789: PHP INI settings would not be passed to child processes. -* Fixed #806: Array references are now properly displayed in error output. -* Fixed #808: Resources are now reported as `resource(13) of type (stream)` instead of `NULL`. -* Fixed: `phpt` test cases now use the correct php binary when executed through wrapper scripts. -* PHPUnit 3.8 is only supported on PHP 5.4.7 (or later). diff --git a/LICENSE b/LICENSE index 7501237f630..b687f39ac47 100644 --- a/LICENSE +++ b/LICENSE @@ -1,33 +1,29 @@ -PHPUnit +BSD 3-Clause License -Copyright (c) 2002-2013, Sebastian Bergmann . +Copyright (c) 2001-2025, Sebastian Bergmann All rights reserved. Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: +modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. - * Neither the name of Sebastian Bergmann nor the names of his - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/PHPUnit/Autoload.php b/PHPUnit/Autoload.php deleted file mode 100644 index fd290360353..00000000000 --- a/PHPUnit/Autoload.php +++ /dev/null @@ -1,256 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -if (defined('PHPUNIT_COMPOSER_INSTALL')) { - return; -} - -$paths = array( - __DIR__ . '/../vendor', - __DIR__ . '/../../..' -); - -foreach ($paths as $path) { - if (is_dir($path . '/composer') && - is_file($path . '/autoload.php')) { - require_once $path . '/autoload.php'; - define('PHPUNIT_COMPOSER_INSTALL', $path . '/autoload.php'); - - return; - } -} - -require_once 'File/Iterator/Autoload.php'; -require_once 'PHP/CodeCoverage/Autoload.php'; -require_once 'PHP/Timer/Autoload.php'; -require_once 'PHPUnit/Framework/MockObject/Autoload.php'; -require_once 'Text/Template/Autoload.php'; -require_once 'SebastianBergmann/Diff/autoload.php'; -require_once 'SebastianBergmann/Exporter/autoload.php'; -require_once 'SebastianBergmann/Version/autoload.php'; - -spl_autoload_register( - function ($class) - { - static $classes = NULL; - static $path = NULL; - - if ($classes === NULL) { - $classes = array( - 'phpunit_extensions_grouptestsuite' => '/Extensions/GroupTestSuite.php', - 'phpunit_extensions_phpttestcase' => '/Extensions/PhptTestCase.php', - 'phpunit_extensions_phpttestcase_logger' => '/Extensions/PhptTestCase/Logger.php', - 'phpunit_extensions_phpttestsuite' => '/Extensions/PhptTestSuite.php', - 'phpunit_extensions_repeatedtest' => '/Extensions/RepeatedTest.php', - 'phpunit_extensions_testdecorator' => '/Extensions/TestDecorator.php', - 'phpunit_extensions_ticketlistener' => '/Extensions/TicketListener.php', - 'phpunit_framework_assert' => '/Framework/Assert.php', - 'phpunit_framework_assertionfailederror' => '/Framework/AssertionFailedError.php', - 'phpunit_framework_basetestlistener' => '/Framework/BaseTestListener.php', - 'phpunit_framework_comparator' => '/Framework/Comparator.php', - 'phpunit_framework_comparator_array' => '/Framework/Comparator/Array.php', - 'phpunit_framework_comparator_domdocument' => '/Framework/Comparator/DOMDocument.php', - 'phpunit_framework_comparator_double' => '/Framework/Comparator/Double.php', - 'phpunit_framework_comparator_exception' => '/Framework/Comparator/Exception.php', - 'phpunit_framework_comparator_mockobject' => '/Framework/Comparator/MockObject.php', - 'phpunit_framework_comparator_numeric' => '/Framework/Comparator/Numeric.php', - 'phpunit_framework_comparator_object' => '/Framework/Comparator/Object.php', - 'phpunit_framework_comparator_resource' => '/Framework/Comparator/Resource.php', - 'phpunit_framework_comparator_scalar' => '/Framework/Comparator/Scalar.php', - 'phpunit_framework_comparator_splobjectstorage' => '/Framework/Comparator/SplObjectStorage.php', - 'phpunit_framework_comparator_type' => '/Framework/Comparator/Type.php', - 'phpunit_framework_comparatorfactory' => '/Framework/ComparatorFactory.php', - 'phpunit_framework_comparisonfailure' => '/Framework/ComparisonFailure.php', - 'phpunit_framework_constraint' => '/Framework/Constraint.php', - 'phpunit_framework_constraint_and' => '/Framework/Constraint/And.php', - 'phpunit_framework_constraint_arrayhaskey' => '/Framework/Constraint/ArrayHasKey.php', - 'phpunit_framework_constraint_attribute' => '/Framework/Constraint/Attribute.php', - 'phpunit_framework_constraint_callback' => '/Framework/Constraint/Callback.php', - 'phpunit_framework_constraint_classhasattribute' => '/Framework/Constraint/ClassHasAttribute.php', - 'phpunit_framework_constraint_classhasstaticattribute' => '/Framework/Constraint/ClassHasStaticAttribute.php', - 'phpunit_framework_constraint_composite' => '/Framework/Constraint/Composite.php', - 'phpunit_framework_constraint_count' => '/Framework/Constraint/Count.php', - 'phpunit_framework_constraint_exception' => '/Framework/Constraint/Exception.php', - 'phpunit_framework_constraint_exceptioncode' => '/Framework/Constraint/ExceptionCode.php', - 'phpunit_framework_constraint_exceptionmessage' => '/Framework/Constraint/ExceptionMessage.php', - 'phpunit_framework_constraint_fileexists' => '/Framework/Constraint/FileExists.php', - 'phpunit_framework_constraint_greaterthan' => '/Framework/Constraint/GreaterThan.php', - 'phpunit_framework_constraint_isanything' => '/Framework/Constraint/IsAnything.php', - 'phpunit_framework_constraint_isempty' => '/Framework/Constraint/IsEmpty.php', - 'phpunit_framework_constraint_isequal' => '/Framework/Constraint/IsEqual.php', - 'phpunit_framework_constraint_isfalse' => '/Framework/Constraint/IsFalse.php', - 'phpunit_framework_constraint_isidentical' => '/Framework/Constraint/IsIdentical.php', - 'phpunit_framework_constraint_isinstanceof' => '/Framework/Constraint/IsInstanceOf.php', - 'phpunit_framework_constraint_isnull' => '/Framework/Constraint/IsNull.php', - 'phpunit_framework_constraint_istrue' => '/Framework/Constraint/IsTrue.php', - 'phpunit_framework_constraint_istype' => '/Framework/Constraint/IsType.php', - 'phpunit_framework_constraint_jsonmatches' => '/Framework/Constraint/JsonMatches.php', - 'phpunit_framework_constraint_jsonmatches_errormessageprovider' => '/Framework/Constraint/JsonMatches/ErrorMessageProvider.php', - 'phpunit_framework_constraint_lessthan' => '/Framework/Constraint/LessThan.php', - 'phpunit_framework_constraint_not' => '/Framework/Constraint/Not.php', - 'phpunit_framework_constraint_objecthasattribute' => '/Framework/Constraint/ObjectHasAttribute.php', - 'phpunit_framework_constraint_or' => '/Framework/Constraint/Or.php', - 'phpunit_framework_constraint_pcrematch' => '/Framework/Constraint/PCREMatch.php', - 'phpunit_framework_constraint_samesize' => '/Framework/Constraint/SameSize.php', - 'phpunit_framework_constraint_stringcontains' => '/Framework/Constraint/StringContains.php', - 'phpunit_framework_constraint_stringendswith' => '/Framework/Constraint/StringEndsWith.php', - 'phpunit_framework_constraint_stringmatches' => '/Framework/Constraint/StringMatches.php', - 'phpunit_framework_constraint_stringstartswith' => '/Framework/Constraint/StringStartsWith.php', - 'phpunit_framework_constraint_traversablecontains' => '/Framework/Constraint/TraversableContains.php', - 'phpunit_framework_constraint_traversablecontainsonly' => '/Framework/Constraint/TraversableContainsOnly.php', - 'phpunit_framework_constraint_xor' => '/Framework/Constraint/Xor.php', - 'phpunit_framework_error' => '/Framework/Error.php', - 'phpunit_framework_error_deprecated' => '/Framework/Error/Deprecated.php', - 'phpunit_framework_error_notice' => '/Framework/Error/Notice.php', - 'phpunit_framework_error_warning' => '/Framework/Error/Warning.php', - 'phpunit_framework_exception' => '/Framework/Exception.php', - 'phpunit_framework_expectationfailedexception' => '/Framework/ExpectationFailedException.php', - 'phpunit_framework_incompletetest' => '/Framework/IncompleteTest.php', - 'phpunit_framework_incompletetesterror' => '/Framework/IncompleteTestError.php', - 'phpunit_framework_invalidcoverstargeterror' => '/Framework/InvalidCoversTargetError.php', - 'phpunit_framework_outputerror' => '/Framework/OutputError.php', - 'phpunit_framework_selfdescribing' => '/Framework/SelfDescribing.php', - 'phpunit_framework_skippedtest' => '/Framework/SkippedTest.php', - 'phpunit_framework_skippedtesterror' => '/Framework/SkippedTestError.php', - 'phpunit_framework_skippedtestsuiteerror' => '/Framework/SkippedTestSuiteError.php', - 'phpunit_framework_syntheticerror' => '/Framework/SyntheticError.php', - 'phpunit_framework_test' => '/Framework/Test.php', - 'phpunit_framework_testcase' => '/Framework/TestCase.php', - 'phpunit_framework_testfailure' => '/Framework/TestFailure.php', - 'phpunit_framework_testlistener' => '/Framework/TestListener.php', - 'phpunit_framework_testresult' => '/Framework/TestResult.php', - 'phpunit_framework_testsuite' => '/Framework/TestSuite.php', - 'phpunit_framework_testsuite_dataprovider' => '/Framework/TestSuite/DataProvider.php', - 'phpunit_framework_unintentionallycoveredcodeerror' => '/Framework/UnintentionallyCoveredCodeError.php', - 'phpunit_framework_warning' => '/Framework/Warning.php', - 'phpunit_runner_basetestrunner' => '/Runner/BaseTestRunner.php', - 'phpunit_runner_filter_factory' => '/Runner/Filter/Factory.php', - 'phpunit_runner_filter_group_exclude' => '/Runner/Filter/Group/Exclude.php', - 'phpunit_runner_filter_group_include' => '/Runner/Filter/Group/Include.php', - 'phpunit_runner_filter_groupfilteriterator' => '/Runner/Filter/Group.php', - 'phpunit_runner_filter_test' => '/Runner/Filter/Test.php', - 'phpunit_runner_standardtestsuiteloader' => '/Runner/StandardTestSuiteLoader.php', - 'phpunit_runner_testsuiteloader' => '/Runner/TestSuiteLoader.php', - 'phpunit_runner_version' => '/Runner/Version.php', - 'phpunit_textui_command' => '/TextUI/Command.php', - 'phpunit_textui_resultprinter' => '/TextUI/ResultPrinter.php', - 'phpunit_textui_testrunner' => '/TextUI/TestRunner.php', - 'phpunit_util_configuration' => '/Util/Configuration.php', - 'phpunit_util_deprecatedfeature' => '/Util/DeprecatedFeature.php', - 'phpunit_util_deprecatedfeature_logger' => '/Util/DeprecatedFeature/Logger.php', - 'phpunit_util_errorhandler' => '/Util/ErrorHandler.php', - 'phpunit_util_fileloader' => '/Util/Fileloader.php', - 'phpunit_util_filesystem' => '/Util/Filesystem.php', - 'phpunit_util_filter' => '/Util/Filter.php', - 'phpunit_util_getopt' => '/Util/Getopt.php', - 'phpunit_util_globalstate' => '/Util/GlobalState.php', - 'phpunit_util_invalidargumenthelper' => '/Util/InvalidArgumentHelper.php', - 'phpunit_util_log_json' => '/Util/Log/JSON.php', - 'phpunit_util_log_junit' => '/Util/Log/JUnit.php', - 'phpunit_util_log_tap' => '/Util/Log/TAP.php', - 'phpunit_util_php' => '/Util/PHP.php', - 'phpunit_util_php_default' => '/Util/PHP/Default.php', - 'phpunit_util_php_windows' => '/Util/PHP/Windows.php', - 'phpunit_util_printer' => '/Util/Printer.php', - 'phpunit_util_string' => '/Util/String.php', - 'phpunit_util_test' => '/Util/Test.php', - 'phpunit_util_testdox_nameprettifier' => '/Util/TestDox/NamePrettifier.php', - 'phpunit_util_testdox_resultprinter' => '/Util/TestDox/ResultPrinter.php', - 'phpunit_util_testdox_resultprinter_html' => '/Util/TestDox/ResultPrinter/HTML.php', - 'phpunit_util_testdox_resultprinter_text' => '/Util/TestDox/ResultPrinter/Text.php', - 'phpunit_util_testsuiteiterator' => '/Util/TestSuiteIterator.php', - 'phpunit_util_type' => '/Util/Type.php', - 'phpunit_util_xml' => '/Util/XML.php' - ); - - $path = dirname(__FILE__); - } - - $cn = strtolower($class); - - if (isset($classes[$cn])) { - require $path . $classes[$cn]; - } - } -); - -// Symfony Yaml autoloader -spl_autoload_register( - function ($class) { - if (0 === strpos(ltrim($class, '/'), 'Symfony\Component\Yaml')) { - $file = sprintf( - 'Symfony/Component/Yaml%s.php', - - substr( - str_replace('\\', '/', $class), - strlen('Symfony\Component\Yaml') - ) - ); - - if (stream_resolve_include_path($file)) { - require_once $file; - } - } - } -); - -if (stream_resolve_include_path('PHP/Invoker/Autoload.php')) { - require_once 'PHP/Invoker/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/Database/Autoload.php')) { - require_once 'PHPUnit/Extensions/Database/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/SeleniumCommon/Autoload.php')) { - require_once 'PHPUnit/Extensions/SeleniumCommon/Autoload.php'; -} - -else if (stream_resolve_include_path('PHPUnit/Extensions/SeleniumTestCase/Autoload.php')) { - require_once 'PHPUnit/Extensions/SeleniumTestCase/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/Story/Autoload.php')) { - require_once 'PHPUnit/Extensions/Story/Autoload.php'; -} diff --git a/PHPUnit/Autoload.php.in b/PHPUnit/Autoload.php.in deleted file mode 100644 index 8af92a0d1d1..00000000000 --- a/PHPUnit/Autoload.php.in +++ /dev/null @@ -1,133 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -if (defined('PHPUNIT_COMPOSER_INSTALL')) { - return; -} - -$paths = array( - __DIR__ . '/../vendor', - __DIR__ . '/../../..' -); - -foreach ($paths as $path) { - if (is_dir($path . '/composer') && - is_file($path . '/autoload.php')) { - require_once $path . '/autoload.php'; - define('PHPUNIT_COMPOSER_INSTALL', $path . '/autoload.php'); - - return; - } -} - -require_once 'File/Iterator/Autoload.php'; -require_once 'PHP/CodeCoverage/Autoload.php'; -require_once 'PHP/Timer/Autoload.php'; -require_once 'PHPUnit/Framework/MockObject/Autoload.php'; -require_once 'Text/Template/Autoload.php'; -require_once 'SebastianBergmann/Diff/autoload.php'; -require_once 'SebastianBergmann/Exporter/autoload.php'; -require_once 'SebastianBergmann/Version/autoload.php'; - -spl_autoload_register( - function ($class) - { - static $classes = NULL; - static $path = NULL; - - if ($classes === NULL) { - $classes = array( - ___CLASSLIST___ - ); - - $path = dirname(__FILE__); - } - - $cn = strtolower($class); - - if (isset($classes[$cn])) { - require $path . $classes[$cn]; - } - } -); - -// Symfony Yaml autoloader -spl_autoload_register( - function ($class) { - if (0 === strpos(ltrim($class, '/'), 'Symfony\Component\Yaml')) { - $file = sprintf( - 'Symfony/Component/Yaml%s.php', - - substr( - str_replace('\\', '/', $class), - strlen('Symfony\Component\Yaml') - ) - ); - - if (stream_resolve_include_path($file)) { - require_once $file; - } - } - } -); - -if (stream_resolve_include_path('PHP/Invoker/Autoload.php')) { - require_once 'PHP/Invoker/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/Database/Autoload.php')) { - require_once 'PHPUnit/Extensions/Database/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/SeleniumCommon/Autoload.php')) { - require_once 'PHPUnit/Extensions/SeleniumCommon/Autoload.php'; -} - -else if (stream_resolve_include_path('PHPUnit/Extensions/SeleniumTestCase/Autoload.php')) { - require_once 'PHPUnit/Extensions/SeleniumTestCase/Autoload.php'; -} - -if (stream_resolve_include_path('PHPUnit/Extensions/Story/Autoload.php')) { - require_once 'PHPUnit/Extensions/Story/Autoload.php'; -} diff --git a/PHPUnit/Extensions/GroupTestSuite.php b/PHPUnit/Extensions/GroupTestSuite.php deleted file mode 100644 index c66112bec05..00000000000 --- a/PHPUnit/Extensions/GroupTestSuite.php +++ /dev/null @@ -1,99 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * We have a TestSuite object A. - * In TestSuite object A we have Tests tagged with @group. - * We want a TestSuite object B that contains TestSuite objects C, D, ... - * for the Tests tagged with @group C, @group D, ... - * Running the Tests from TestSuite object B results in Tests tagged with both - * @group C and @group D in TestSuite object A to be run twice . - * - * - * $suite = new PHPUnit_Extensions_GroupTestSuite($A, array('C', 'D')); - * - * - * @package PHPUnit - * @subpackage Extensions - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Extensions_GroupTestSuite extends PHPUnit_Framework_TestSuite -{ - public function __construct(PHPUnit_Framework_TestSuite $suite, array $groups) - { - $groupSuites = array(); - $name = $suite->getName(); - - foreach ($groups as $group) { - $groupSuites[$group] = new PHPUnit_Framework_TestSuite($name . ' - ' . $group); - $this->addTest($groupSuites[$group]); - } - - $tests = new RecursiveIteratorIterator( - new PHPUnit_Util_TestSuiteIterator($suite), - RecursiveIteratorIterator::LEAVES_ONLY - ); - - foreach ($tests as $test) { - if ($test instanceof PHPUnit_Framework_TestCase) { - $testGroups = PHPUnit_Util_Test::getGroups( - get_class($test), $test->getName(FALSE) - ); - - foreach ($groups as $group) { - foreach ($testGroups as $testGroup) { - if ($group == $testGroup) { - $groupSuites[$group]->addTest($test); - } - } - } - } - } - } -} diff --git a/PHPUnit/Extensions/PhptTestCase.php b/PHPUnit/Extensions/PhptTestCase.php deleted file mode 100644 index a18dd38157b..00000000000 --- a/PHPUnit/Extensions/PhptTestCase.php +++ /dev/null @@ -1,271 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.4 - */ - -if (stream_resolve_include_path('PEAR/RunTest.php')) { - $currentErrorReporting = error_reporting(E_ERROR | E_WARNING | E_PARSE); - require_once 'PEAR/RunTest.php'; - error_reporting($currentErrorReporting); -} - -/** - * Wrapper to run .phpt test cases. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.4 - */ -class PHPUnit_Extensions_PhptTestCase implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing -{ - /** - * The filename of the .phpt file. - * - * @var string - */ - protected $filename; - - /** - * Options for PEAR_RunTest. - * - * @var array - */ - protected $options = array(); - - /** - * Constructs a test case with the given filename. - * - * @param string $filename - * @param array $options - */ - public function __construct($filename, array $options = array()) - { - if (!is_string($filename)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_file($filename)) { - throw new PHPUnit_Framework_Exception( - sprintf( - 'File "%s" does not exist.', - $filename - ) - ); - } - - $this->filename = $filename; - $this->options = $options; - } - - /** - * Counts the number of test cases executed by run(TestResult result). - * - * @return integer - */ - public function count() - { - return 1; - } - - /** - * Runs a test and collects its result in a TestResult instance. - * - * @param PHPUnit_Framework_TestResult $result - * @param array $options - * @return PHPUnit_Framework_TestResult - */ - public function run(PHPUnit_Framework_TestResult $result = NULL, array $options = array()) - { - if (!class_exists('PEAR_RunTest', FALSE)) { - throw new PHPUnit_Framework_Exception('Class PEAR_RunTest not found.'); - } - - if (isset($GLOBALS['_PEAR_destructor_object_list']) && - is_array($GLOBALS['_PEAR_destructor_object_list']) && - !empty($GLOBALS['_PEAR_destructor_object_list'])) { - $pearDestructorObjectListCount = count($GLOBALS['_PEAR_destructor_object_list']); - } else { - $pearDestructorObjectListCount = 0; - } - - if ($result === NULL) { - $result = new PHPUnit_Framework_TestResult; - } - - $coverage = $result->getCollectCodeCoverageInformation(); - $options = array_merge($options, $this->options); - - if (!isset($options['include_path'])) { - $options['include_path'] = get_include_path(); - } - - if ($coverage) { - $options['coverage'] = TRUE; - } else { - $options['coverage'] = FALSE; - } - - $currentErrorReporting = error_reporting(E_ERROR | E_WARNING | E_PARSE); - $runner = new PEAR_RunTest(new PHPUnit_Extensions_PhptTestCase_Logger, $options); - - if ($coverage) { - $runner->xdebug_loaded = TRUE; - } else { - $runner->xdebug_loaded = FALSE; - } - - $result->startTest($this); - - $timer = new PHP_Timer; - $timer->start(); - - $runner->_php = escapeshellarg(PHP_BINARY); - $buffer = $runner->run($this->filename, $options); - $time = $timer->stop(); - - error_reporting($currentErrorReporting); - - $base = basename($this->filename); - $path = dirname($this->filename); - $coverageFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.xdebug', $base - ); - $diffFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.diff', $base - ); - $expFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.exp', $base - ); - $logFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.log', $base - ); - $outFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.out', $base - ); - $phpFile = $path . DIRECTORY_SEPARATOR . str_replace( - '.phpt', '.php', $base - ); - - if (is_object($buffer) && $buffer instanceof PEAR_Error) { - $result->addError( - $this, - new PHPUnit_Framework_Exception($buffer->getMessage()), - $time - ); - } - - else if ($buffer == 'SKIPPED') { - $result->addFailure($this, new PHPUnit_Framework_SkippedTestError, 0); - } - - else if ($buffer != 'PASSED') { - $expContent = file_get_contents($expFile); - $outContent = file_get_contents($outFile); - - $result->addFailure( - $this, - new PHPUnit_Framework_ComparisonFailure( - $expContent, - $outContent, - $expContent, - $outContent - ), - $time - ); - } - - foreach (array($diffFile, $expFile, $logFile, $phpFile, $outFile) as $file) { - if (file_exists($file)) { - unlink($file); - } - } - - if ($coverage && file_exists($coverageFile)) { - eval('$coverageData = ' . file_get_contents($coverageFile) . ';'); - unset($coverageData[$phpFile]); - - $result->getCodeCoverage()->append($coverageData, $this); - unlink($coverageFile); - } - - $result->endTest($this, $time); - - // Do not invoke PEAR's destructor mechanism for PHP 4 - // as it raises an E_STRICT. - if ($pearDestructorObjectListCount == 0) { - unset($GLOBALS['_PEAR_destructor_object_list']); - } else { - $count = count($GLOBALS['_PEAR_destructor_object_list']) - $pearDestructorObjectListCount; - - for ($i = 0; $i < $count; $i++) { - array_pop($GLOBALS['_PEAR_destructor_object_list']); - } - } - - return $result; - } - - /** - * Returns the name of the test case. - * - * @return string - */ - public function getName() - { - return $this->toString(); - } - - /** - * Returns a string representation of the test case. - * - * @return string - */ - public function toString() - { - return $this->filename; - } -} diff --git a/PHPUnit/Extensions/PhptTestCase/Logger.php b/PHPUnit/Extensions/PhptTestCase/Logger.php deleted file mode 100644 index f8eda20c1b5..00000000000 --- a/PHPUnit/Extensions/PhptTestCase/Logger.php +++ /dev/null @@ -1,62 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.4 - */ - -/** - * Dummy logger for PEAR_RunTest. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.4 - */ -class PHPUnit_Extensions_PhptTestCase_Logger -{ - public function log($level, $msg, $append_crlf = TRUE) - { - } -} diff --git a/PHPUnit/Extensions/PhptTestSuite.php b/PHPUnit/Extensions/PhptTestSuite.php deleted file mode 100644 index e07227e1e8b..00000000000 --- a/PHPUnit/Extensions/PhptTestSuite.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.4 - */ - -/** - * Suite for .phpt test cases. - * - * @package PHPUnit - * @subpackage Extensions_PhptTestCase - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.4 - */ -class PHPUnit_Extensions_PhptTestSuite extends PHPUnit_Framework_TestSuite -{ - /** - * Constructs a new TestSuite for .phpt test cases. - * - * @param string $directory - * @param array $options Array with ini settings for the php instance run, - * key being the name if the setting, value the ini value. - * @throws PHPUnit_Framework_Exception - */ - public function __construct($directory, array $options = array()) - { - if (is_string($directory) && is_dir($directory)) { - $this->setName($directory); - - $facade = new File_Iterator_Facade; - $files = $facade->getFilesAsArray($directory, '.phpt'); - - foreach ($files as $file) { - $this->addTestFile($file, $options); - } - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'directory name'); - } - } -} diff --git a/PHPUnit/Extensions/RepeatedTest.php b/PHPUnit/Extensions/RepeatedTest.php deleted file mode 100644 index f12c07afaeb..00000000000 --- a/PHPUnit/Extensions/RepeatedTest.php +++ /dev/null @@ -1,145 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A Decorator that runs a test repeatedly. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Extensions_RepeatedTest extends PHPUnit_Extensions_TestDecorator -{ - /** - * @var mixed - */ - protected $filter = FALSE; - - /** - * @var array - */ - protected $groups = array(); - - /** - * @var array - */ - protected $excludeGroups = array(); - - /** - * @var boolean - */ - protected $processIsolation = FALSE; - - /** - * @var integer - */ - protected $timesRepeat = 1; - - /** - * Constructor. - * - * @param PHPUnit_Framework_Test $test - * @param integer $timesRepeat - * @param mixed $filter - * @param array $groups - * @param array $excludeGroups - * @param boolean $processIsolation - * @throws PHPUnit_Framework_Exception - */ - public function __construct(PHPUnit_Framework_Test $test, $timesRepeat = 1, $processIsolation = FALSE) - { - parent::__construct($test); - - if (is_integer($timesRepeat) && - $timesRepeat >= 0) { - $this->timesRepeat = $timesRepeat; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'positive integer' - ); - } - - $this->processIsolation = $processIsolation; - } - - /** - * Counts the number of test cases that - * will be run by this test. - * - * @return integer - */ - public function count() - { - return $this->timesRepeat * count($this->test); - } - - /** - * Runs the decorated test and collects the - * result in a TestResult. - * - * @param PHPUnit_Framework_TestResult $result - * @return PHPUnit_Framework_TestResult - * @throws PHPUnit_Framework_Exception - */ - public function run(PHPUnit_Framework_TestResult $result = NULL) - { - if ($result === NULL) { - $result = $this->createResult(); - } - - //@codingStandardsIgnoreStart - for ($i = 0; $i < $this->timesRepeat && !$result->shouldStop(); $i++) { - //@codingStandardsIgnoreEnd - if ($this->test instanceof PHPUnit_Framework_TestSuite) { - $this->test->setRunTestInSeparateProcess($this->processIsolation); - } - $this->test->run($result); - } - - return $result; - } -} diff --git a/PHPUnit/Extensions/TestDecorator.php b/PHPUnit/Extensions/TestDecorator.php deleted file mode 100644 index 37fb9d16ce0..00000000000 --- a/PHPUnit/Extensions/TestDecorator.php +++ /dev/null @@ -1,149 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A Decorator for Tests. - * - * Use TestDecorator as the base class for defining new - * test decorators. Test decorator subclasses can be introduced - * to add behaviour before or after a test is run. - * - * @package PHPUnit - * @subpackage Extensions - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Extensions_TestDecorator extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing -{ - /** - * The Test to be decorated. - * - * @var object - */ - protected $test = NULL; - - /** - * Constructor. - * - * @param PHPUnit_Framework_Test $test - */ - public function __construct(PHPUnit_Framework_Test $test) - { - $this->test = $test; - } - - /** - * Returns a string representation of the test. - * - * @return string - */ - public function toString() - { - return $this->test->toString(); - } - - /** - * Runs the test and collects the - * result in a TestResult. - * - * @param PHPUnit_Framework_TestResult $result - */ - public function basicRun(PHPUnit_Framework_TestResult $result) - { - $this->test->run($result); - } - - /** - * Counts the number of test cases that - * will be run by this test. - * - * @return integer - */ - public function count() - { - return count($this->test); - } - - /** - * Creates a default TestResult object. - * - * @return PHPUnit_Framework_TestResult - */ - protected function createResult() - { - return new PHPUnit_Framework_TestResult; - } - - /** - * Returns the test to be run. - * - * @return PHPUnit_Framework_Test - */ - public function getTest() - { - return $this->test; - } - - /** - * Runs the decorated test and collects the - * result in a TestResult. - * - * @param PHPUnit_Framework_TestResult $result - * @return PHPUnit_Framework_TestResult - */ - public function run(PHPUnit_Framework_TestResult $result = NULL) - { - if ($result === NULL) { - $result = $this->createResult(); - } - - $this->basicRun($result); - - return $result; - } -} diff --git a/PHPUnit/Extensions/TicketListener.php b/PHPUnit/Extensions/TicketListener.php deleted file mode 100644 index d7d468a43f7..00000000000 --- a/PHPUnit/Extensions/TicketListener.php +++ /dev/null @@ -1,224 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Extensions_TicketListener - * @author Sean Coates - * @author Raphael Stolt - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Base class for test listeners that interact with an issue tracker. - * - * @package PHPUnit - * @subpackage Extensions_TicketListener - * @author Sean Coates - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -abstract class PHPUnit_Extensions_TicketListener implements PHPUnit_Framework_TestListener -{ - /** - * @var array - */ - protected $ticketCounts = array(); - - /** - * @var boolean - */ - protected $ran = FALSE; - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * A test suite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test suite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - if (!$test instanceof PHPUnit_Framework_Warning) { - if ($this->ran) { - return; - } - - $name = $test->getName(FALSE); - $tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name); - - foreach ($tickets as $ticket) { - $this->ticketCounts[$ticket][$name] = 1; - } - - $this->ran = TRUE; - } - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if (!$test instanceof PHPUnit_Framework_Warning) { - if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { - $ifStatus = array('assigned', 'new', 'reopened'); - $newStatus = 'closed'; - $message = 'Automatically closed by PHPUnit (test passed).'; - $resolution = 'fixed'; - $cumulative = TRUE; - } - - else if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE) { - $ifStatus = array('closed'); - $newStatus = 'reopened'; - $message = 'Automatically reopened by PHPUnit (test failed).'; - $resolution = ''; - $cumulative = FALSE; - } - - else { - return; - } - - $name = $test->getName(FALSE); - $tickets = PHPUnit_Util_Test::getTickets(get_class($test), $name); - - foreach ($tickets as $ticket) { - // Remove this test from the totals (if it passed). - if ($test->getStatus() == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { - unset($this->ticketCounts[$ticket][$name]); - } - - // Only close tickets if ALL referenced cases pass - // but reopen tickets if a single test fails. - if ($cumulative) { - // Determine number of to-pass tests: - if (count($this->ticketCounts[$ticket]) > 0) { - // There exist remaining test cases with this reference. - $adjustTicket = FALSE; - } else { - // No remaining tickets, go ahead and adjust. - $adjustTicket = TRUE; - } - } else { - $adjustTicket = TRUE; - } - - $ticketInfo = $this->getTicketInfo($ticket); - - if ($adjustTicket && in_array($ticketInfo['status'], $ifStatus)) { - $this->updateTicket($ticket, $newStatus, $message, $resolution); - } - } - } - } - - abstract protected function getTicketInfo($ticketId = NULL); - abstract protected function updateTicket($ticketId, $newStatus, $message, $resolution); -} diff --git a/PHPUnit/Framework/Assert.php b/PHPUnit/Framework/Assert.php deleted file mode 100644 index 9424d7080d2..00000000000 --- a/PHPUnit/Framework/Assert.php +++ /dev/null @@ -1,2979 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A set of assert methods. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -abstract class PHPUnit_Framework_Assert -{ - /** - * @var integer - */ - private static $count = 0; - - /** - * Asserts that an array has a specified key. - * - * @param mixed $key - * @param array|ArrayAccess $array - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertArrayHasKey($key, $array, $message = '') - { - if (!(is_integer($key) || is_string($key))) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'integer or string' - ); - } - if (!(is_array($array) || $array instanceof ArrayAccess)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array or ArrayAccess' - ); - } - - $constraint = new PHPUnit_Framework_Constraint_ArrayHasKey($key); - - self::assertThat($array, $constraint, $message); - } - - /** - * Asserts that an array does not have a specified key. - * - * @param mixed $key - * @param array|ArrayAccess $array - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertArrayNotHasKey($key, $array, $message = '') - { - if (!(is_integer($key) || is_string($key))) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'integer or string' - ); - } - if (!(is_array($array) || $array instanceof ArrayAccess)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array or ArrayAccess' - ); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_ArrayHasKey($key) - ); - - self::assertThat($array, $constraint, $message); - } - - /** - * Asserts that a haystack contains a needle. - * - * @param mixed $needle - * @param mixed $haystack - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 2.1.0 - */ - public static function assertContains($needle, $haystack, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - if (is_array($haystack) || - is_object($haystack) && $haystack instanceof Traversable) { - $constraint = new PHPUnit_Framework_Constraint_TraversableContains( - $needle, $checkForObjectIdentity, $checkForNonObjectIdentity - ); - } - - else if (is_string($haystack)) { - $constraint = new PHPUnit_Framework_Constraint_StringContains( - $needle, $ignoreCase - ); - } - - else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array, iterator or string' - ); - } - - self::assertThat($haystack, $constraint, $message); - } - - /** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object contains a needle. - * - * @param mixed $needle - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 3.0.0 - */ - public static function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - self::assertContains( - $needle, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message, - $ignoreCase, - $checkForObjectIdentity, - $checkForNonObjectIdentity - ); - } - - /** - * Asserts that a haystack does not contain a needle. - * - * @param mixed $needle - * @param mixed $haystack - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 2.1.0 - */ - public static function assertNotContains($needle, $haystack, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - if (is_array($haystack) || - is_object($haystack) && $haystack instanceof Traversable) { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_TraversableContains( - $needle, $checkForObjectIdentity, $checkForNonObjectIdentity - ) - ); - } - - else if (is_string($haystack)) { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_StringContains( - $needle, $ignoreCase - ) - ); - } - - else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array, iterator or string' - ); - } - - self::assertThat($haystack, $constraint, $message); - } - - /** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object does not contain a needle. - * - * @param mixed $needle - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 3.0.0 - */ - public static function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - self::assertNotContains( - $needle, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message, - $ignoreCase, - $checkForObjectIdentity, - $checkForNonObjectIdentity - ); - } - - /** - * Asserts that a haystack contains only values of a given type. - * - * @param string $type - * @param mixed $haystack - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ - public static function assertContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') - { - if (!(is_array($haystack) || - is_object($haystack) && $haystack instanceof Traversable)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array or iterator' - ); - } - - if ($isNativeType == NULL) { - $isNativeType = PHPUnit_Util_Type::isType($type); - } - - self::assertThat( - $haystack, - new PHPUnit_Framework_Constraint_TraversableContainsOnly( - $type, $isNativeType - ), - $message - ); - } - - /** - * Asserts that a haystack contains only instances of a given classname - * - * @param string $classname - * @param array|Traversable $haystack - * @param string $message - */ - public static function assertContainsOnlyInstancesOf($classname, $haystack, $message = '') - { - if (!(is_array($haystack) || - is_object($haystack) && $haystack instanceof Traversable)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array or iterator' - ); - } - - self::assertThat( - $haystack, - new PHPUnit_Framework_Constraint_TraversableContainsOnly( - $classname, FALSE - ), - $message - ); - } - - /** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object contains only values of a given type. - * - * @param string $type - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ - public static function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') - { - self::assertContainsOnly( - $type, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $isNativeType, - $message - ); - } - - /** - * Asserts that a haystack does not contain only values of a given type. - * - * @param string $type - * @param mixed $haystack - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ - public static function assertNotContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') - { - if (!(is_array($haystack) || - is_object($haystack) && $haystack instanceof Traversable)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 2, 'array or iterator' - ); - } - - if ($isNativeType == NULL) { - $isNativeType = PHPUnit_Util_Type::isType($type); - } - - self::assertThat( - $haystack, - new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_TraversableContainsOnly( - $type, $isNativeType - ) - ), - $message - ); - } - - /** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object does not contain only values of a given - * type. - * - * @param string $type - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ - public static function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') - { - self::assertNotContainsOnly( - $type, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $isNativeType, - $message - ); - } - - /** - * Asserts the number of elements of an array, Countable or Iterator. - * - * @param integer $expectedCount - * @param mixed $haystack - * @param string $message - */ - public static function assertCount($expectedCount, $haystack, $message = '') - { - if (!is_int($expectedCount)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); - } - - if (!$haystack instanceof Countable && - !$haystack instanceof Iterator && - !is_array($haystack)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable'); - } - - self::assertThat( - $haystack, - new PHPUnit_Framework_Constraint_Count($expectedCount), - $message - ); - } - - /** - * Asserts the number of elements of an array, Countable or Iterator - * that is stored in an attribute. - * - * @param integer $expectedCount - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.6.0 - */ - public static function assertAttributeCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '') - { - self::assertCount( - $expectedCount, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message - ); - } - - /** - * Asserts the number of elements of an array, Countable or Iterator. - * - * @param integer $expectedCount - * @param mixed $haystack - * @param string $message - */ - public static function assertNotCount($expectedCount, $haystack, $message = '') - { - if (!is_int($expectedCount)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); - } - - if (!$haystack instanceof Countable && - !$haystack instanceof Iterator && - !is_array($haystack)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_Count($expectedCount) - ); - - self::assertThat($haystack, $constraint, $message); - } - - /** - * Asserts the number of elements of an array, Countable or Iterator - * that is stored in an attribute. - * - * @param integer $expectedCount - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.6.0 - */ - public static function assertAttributeNotCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '') - { - self::assertNotCount( - $expectedCount, - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message - ); - } - - /** - * Asserts that two variables are equal. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ - public static function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - $constraint = new PHPUnit_Framework_Constraint_IsEqual( - $expected, $delta, $maxDepth, $canonicalize, $ignoreCase - ); - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that a variable is equal to an attribute of an object. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ - public static function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertEquals( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message, - $delta, - $maxDepth, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that two variables are not equal. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 2.3.0 - */ - public static function assertNotEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_IsEqual( - $expected, $delta, $maxDepth, $canonicalize, $ignoreCase - ) - ); - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that a variable is not equal to an attribute of an object. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ - public static function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertNotEquals( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message, - $delta, - $maxDepth, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that a variable is empty. - * - * @param mixed $actual - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ - public static function assertEmpty($actual, $message = '') - { - self::assertThat($actual, self::isEmpty(), $message); - } - - /** - * Asserts that a static attribute of a class or an attribute of an object - * is empty. - * - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') - { - self::assertEmpty( - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message - ); - } - - /** - * Asserts that a variable is not empty. - * - * @param mixed $actual - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ - public static function assertNotEmpty($actual, $message = '') - { - self::assertThat($actual, self::logicalNot(self::isEmpty()), $message); - } - - /** - * Asserts that a static attribute of a class or an attribute of an object - * is not empty. - * - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') - { - self::assertNotEmpty( - self::readAttribute($haystackClassOrObject, $haystackAttributeName), - $message - ); - } - - /** - * Asserts that a value is greater than another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertGreaterThan($expected, $actual, $message = '') - { - self::assertThat($actual, self::greaterThan($expected), $message); - } - - /** - * Asserts that an attribute is greater than another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertGreaterThan( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that a value is greater than or equal to another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertGreaterThanOrEqual($expected, $actual, $message = '') - { - self::assertThat( - $actual, self::greaterThanOrEqual($expected), $message - ); - } - - /** - * Asserts that an attribute is greater than or equal to another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertGreaterThanOrEqual( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that a value is smaller than another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertLessThan($expected, $actual, $message = '') - { - self::assertThat($actual, self::lessThan($expected), $message); - } - - /** - * Asserts that an attribute is smaller than another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertLessThan( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that a value is smaller than or equal to another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertLessThanOrEqual($expected, $actual, $message = '') - { - self::assertThat($actual, self::lessThanOrEqual($expected), $message); - } - - /** - * Asserts that an attribute is smaller than or equal to another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertLessThanOrEqual( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that the contents of one file is equal to the contents of another - * file. - * - * @param string $expected - * @param string $actual - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.2.14 - */ - public static function assertFileEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertFileExists($expected, $message); - self::assertFileExists($actual, $message); - - self::assertEquals( - file_get_contents($expected), - file_get_contents($actual), - $message, - 0, - 10, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that the contents of one file is not equal to the contents of - * another file. - * - * @param string $expected - * @param string $actual - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.2.14 - */ - public static function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertFileExists($expected, $message); - self::assertFileExists($actual, $message); - - self::assertNotEquals( - file_get_contents($expected), - file_get_contents($actual), - $message, - 0, - 10, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that the contents of a string is equal - * to the contents of a file. - * - * @param string $expectedFile - * @param string $actualString - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.3.0 - */ - public static function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertFileExists($expectedFile, $message); - - self::assertEquals( - file_get_contents($expectedFile), - $actualString, - $message, - 0, - 10, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that the contents of a string is not equal - * to the contents of a file. - * - * @param string $expectedFile - * @param string $actualString - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.3.0 - */ - public static function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) - { - self::assertFileExists($expectedFile, $message); - - self::assertNotEquals( - file_get_contents($expectedFile), - $actualString, - $message, - 0, - 10, - $canonicalize, - $ignoreCase - ); - } - - /** - * Asserts that a file exists. - * - * @param string $filename - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertFileExists($filename, $message = '') - { - if (!is_string($filename)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_FileExists; - - self::assertThat($filename, $constraint, $message); - } - - /** - * Asserts that a file does not exist. - * - * @param string $filename - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertFileNotExists($filename, $message = '') - { - if (!is_string($filename)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_FileExists - ); - - self::assertThat($filename, $constraint, $message); - } - - /** - * Asserts that a condition is true. - * - * @param boolean $condition - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ - public static function assertTrue($condition, $message = '') - { - self::assertThat($condition, self::isTrue(), $message); - } - - /** - * Asserts that a condition is false. - * - * @param boolean $condition - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ - public static function assertFalse($condition, $message = '') - { - self::assertThat($condition, self::isFalse(), $message); - } - - /** - * Asserts that a variable is not NULL. - * - * @param mixed $actual - * @param string $message - */ - public static function assertNotNull($actual, $message = '') - { - self::assertThat($actual, self::logicalNot(self::isNull()), $message); - } - - /** - * Asserts that a variable is NULL. - * - * @param mixed $actual - * @param string $message - */ - public static function assertNull($actual, $message = '') - { - self::assertThat($actual, self::isNull(), $message); - } - - /** - * Asserts that a class has a specified attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertClassHasAttribute($attributeName, $className, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_string($className) || !class_exists($className, FALSE)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); - } - - $constraint = new PHPUnit_Framework_Constraint_ClassHasAttribute( - $attributeName - ); - - self::assertThat($className, $constraint, $message); - } - - /** - * Asserts that a class does not have a specified attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertClassNotHasAttribute($attributeName, $className, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_string($className) || !class_exists($className, FALSE)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_ClassHasAttribute($attributeName) - ); - - self::assertThat($className, $constraint, $message); - } - - /** - * Asserts that a class has a specified static attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertClassHasStaticAttribute($attributeName, $className, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_string($className) || !class_exists($className, FALSE)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); - } - - $constraint = new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( - $attributeName - ); - - self::assertThat($className, $constraint, $message); - } - - /** - * Asserts that a class does not have a specified static attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertClassNotHasStaticAttribute($attributeName, $className, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_string($className) || !class_exists($className, FALSE)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'class name'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( - $attributeName - ) - ); - - self::assertThat($className, $constraint, $message); - } - - /** - * Asserts that an object has a specified attribute. - * - * @param string $attributeName - * @param object $object - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertObjectHasAttribute($attributeName, $object, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_object($object)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object'); - } - - $constraint = new PHPUnit_Framework_Constraint_ObjectHasAttribute( - $attributeName - ); - - self::assertThat($object, $constraint, $message); - } - - /** - * Asserts that an object does not have a specified attribute. - * - * @param string $attributeName - * @param object $object - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertObjectNotHasAttribute($attributeName, $object, $message = '') - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'valid attribute name'); - } - - if (!is_object($object)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'object'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_ObjectHasAttribute($attributeName) - ); - - self::assertThat($object, $constraint, $message); - } - - /** - * Asserts that two variables have the same type and value. - * Used on objects, it asserts that two variables reference - * the same object. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - */ - public static function assertSame($expected, $actual, $message = '') - { - if (is_bool($expected) && is_bool($actual)) { - self::assertEquals($expected, $actual, $message); - } else { - $constraint = new PHPUnit_Framework_Constraint_IsIdentical( - $expected - ); - - self::assertThat($actual, $constraint, $message); - } - } - - /** - * Asserts that a variable and an attribute of an object have the same type - * and value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param object $actualClassOrObject - * @param string $message - */ - public static function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertSame( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that two variables do not have the same type and value. - * Used on objects, it asserts that two variables do not reference - * the same object. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - */ - public static function assertNotSame($expected, $actual, $message = '') - { - if (is_bool($expected) && is_bool($actual)) { - self::assertNotEquals($expected, $actual, $message); - } else { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_IsIdentical($expected) - ); - - self::assertThat($actual, $constraint, $message); - } - } - - /** - * Asserts that a variable and an attribute of an object do not have the - * same type and value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param object $actualClassOrObject - * @param string $message - */ - public static function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') - { - self::assertNotSame( - $expected, - self::readAttribute($actualClassOrObject, $actualAttributeName), - $message - ); - } - - /** - * Asserts that a variable is of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertInstanceOf($expected, $actual, $message = '') - { - if (is_string($expected)) { - if (class_exists($expected) || interface_exists($expected)) { - $constraint = new PHPUnit_Framework_Constraint_IsInstanceOf( - $expected - ); - } - - else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'class or interface name' - ); - } - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '') - { - self::assertInstanceOf( - $expected, - self::readAttribute($classOrObject, $attributeName), - $message - ); - } - - /** - * Asserts that a variable is not of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertNotInstanceOf($expected, $actual, $message = '') - { - if (is_string($expected)) { - if (class_exists($expected) || interface_exists($expected)) { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_IsInstanceOf($expected) - ); - } - - else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'class or interface name' - ); - } - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '') - { - self::assertNotInstanceOf( - $expected, - self::readAttribute($classOrObject, $attributeName), - $message - ); - } - - /** - * Asserts that a variable is of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertInternalType($expected, $actual, $message = '') - { - if (is_string($expected)) { - $constraint = new PHPUnit_Framework_Constraint_IsType( - $expected - ); - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '') - { - self::assertInternalType( - $expected, - self::readAttribute($classOrObject, $attributeName), - $message - ); - } - - /** - * Asserts that a variable is not of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertNotInternalType($expected, $actual, $message = '') - { - if (is_string($expected)) { - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_IsType($expected) - ); - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '') - { - self::assertNotInternalType( - $expected, - self::readAttribute($classOrObject, $attributeName), - $message - ); - } - - /** - * Asserts that a string matches a given regular expression. - * - * @param string $pattern - * @param string $string - * @param string $message - */ - public static function assertRegExp($pattern, $string, $message = '') - { - if (!is_string($pattern)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_PCREMatch($pattern); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string does not match a given regular expression. - * - * @param string $pattern - * @param string $string - * @param string $message - * @since Method available since Release 2.1.0 - */ - public static function assertNotRegExp($pattern, $string, $message = '') - { - if (!is_string($pattern)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_PCREMatch($pattern) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Assert that the size of two arrays (or `Countable` or `Iterator` objects) - * is the same. - * - * @param array|Countable|Iterator $expected - * @param array|Countable|Iterator $actual - * @param string $message - */ - public static function assertSameSize($expected, $actual, $message = '') - { - if (!$expected instanceof Countable && - !$expected instanceof Iterator && - !is_array($expected)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'countable'); - } - - if (!$actual instanceof Countable && - !$actual instanceof Iterator && - !is_array($actual)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable'); - } - - self::assertThat( - $actual, - new PHPUnit_Framework_Constraint_SameSize($expected), - $message - ); - } - - /** - * Assert that the size of two arrays (or `Countable` or `Iterator` objects) - * is not the same. - * - * @param array|Countable|Iterator $expected - * @param array|Countable|Iterator $actual - * @param string $message - */ - public static function assertNotSameSize($expected, $actual, $message = '') - { - if (!$expected instanceof Countable && - !$expected instanceof Iterator && - !is_array($expected)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'countable'); - } - - if (!$actual instanceof Countable && - !$actual instanceof Iterator && - !is_array($actual)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'countable'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_SameSize($expected) - ); - - self::assertThat($actual, $constraint, $message); - } - - /** - * Asserts that a string matches a given format string. - * - * @param string $format - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertStringMatchesFormat($format, $string, $message = '') - { - if (!is_string($format)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_StringMatches($format); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string does not match a given format string. - * - * @param string $format - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertStringNotMatchesFormat($format, $string, $message = '') - { - if (!is_string($format)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_StringMatches($format) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string matches a given format file. - * - * @param string $formatFile - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertStringMatchesFormatFile($formatFile, $string, $message = '') - { - self::assertFileExists($formatFile, $message); - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_StringMatches( - file_get_contents($formatFile) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string does not match a given format string. - * - * @param string $formatFile - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ - public static function assertStringNotMatchesFormatFile($formatFile, $string, $message = '') - { - self::assertFileExists($formatFile, $message); - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_StringMatches( - file_get_contents($formatFile) - ) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string starts with a given prefix. - * - * @param string $prefix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ - public static function assertStringStartsWith($prefix, $string, $message = '') - { - if (!is_string($prefix)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_StringStartsWith( - $prefix - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string starts not with a given prefix. - * - * @param string $prefix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ - public static function assertStringStartsNotWith($prefix, $string, $message = '') - { - if (!is_string($prefix)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_StringStartsWith($prefix) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string ends with a given prefix. - * - * @param string $suffix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ - public static function assertStringEndsWith($suffix, $string, $message = '') - { - if (!is_string($suffix)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_StringEndsWith($suffix); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that a string ends not with a given prefix. - * - * @param string $suffix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ - public static function assertStringEndsNotWith($suffix, $string, $message = '') - { - if (!is_string($suffix)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!is_string($string)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - $constraint = new PHPUnit_Framework_Constraint_Not( - new PHPUnit_Framework_Constraint_StringEndsWith($suffix) - ); - - self::assertThat($string, $constraint, $message); - } - - /** - * Asserts that two XML files are equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '') - { - self::assertFileExists($expectedFile); - self::assertFileExists($actualFile); - - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->load($expectedFile); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->load($actualFile); - - self::assertEquals($expected, $actual, $message); - } - - /** - * Asserts that two XML files are not equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '') - { - self::assertFileExists($expectedFile); - self::assertFileExists($actualFile); - - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->load($expectedFile); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->load($actualFile); - - self::assertNotEquals($expected, $actual, $message); - } - - /** - * Asserts that two XML documents are equal. - * - * @param string $expectedFile - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.3.0 - */ - public static function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '') - { - self::assertFileExists($expectedFile); - - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->load($expectedFile); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->loadXML($actualXml); - - self::assertEquals($expected, $actual, $message); - } - - /** - * Asserts that two XML documents are not equal. - * - * @param string $expectedFile - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.3.0 - */ - public static function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '') - { - self::assertFileExists($expectedFile); - - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->load($expectedFile); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->loadXML($actualXml); - - self::assertNotEquals($expected, $actual, $message); - } - - /** - * Asserts that two XML documents are equal. - * - * @param string $expectedXml - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '') - { - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->loadXML($expectedXml); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->loadXML($actualXml); - - self::assertEquals($expected, $actual, $message); - } - - /** - * Asserts that two XML documents are not equal. - * - * @param string $expectedXml - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.1.0 - */ - public static function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '') - { - $expected = new DOMDocument; - $expected->preserveWhiteSpace = FALSE; - $expected->loadXML($expectedXml); - - $actual = new DOMDocument; - $actual->preserveWhiteSpace = FALSE; - $actual->loadXML($actualXml); - - self::assertNotEquals($expected, $actual, $message); - } - - /** - * Asserts that a hierarchy of DOMElements matches. - * - * @param DOMElement $expectedElement - * @param DOMElement $actualElement - * @param boolean $checkAttributes - * @param string $message - * @author Mattis Stordalen Flister - * @since Method available since Release 3.3.0 - */ - public static function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, $checkAttributes = FALSE, $message = '') - { - self::assertEquals( - $expectedElement->tagName, - $actualElement->tagName, - $message - ); - - if ($checkAttributes) { - self::assertEquals( - $expectedElement->attributes->length, - $actualElement->attributes->length, - sprintf( - '%s%sNumber of attributes on node "%s" does not match', - $message, - !empty($message) ? "\n" : '', - $expectedElement->tagName - ) - ); - - for ($i = 0 ; $i < $expectedElement->attributes->length; $i++) { - $expectedAttribute = $expectedElement->attributes->item($i); - $actualAttribute = $actualElement->attributes->getNamedItem( - $expectedAttribute->name - ); - - if (!$actualAttribute) { - self::fail( - sprintf( - '%s%sCould not find attribute "%s" on node "%s"', - $message, - !empty($message) ? "\n" : '', - $expectedAttribute->name, - $expectedElement->tagName - ) - ); - } - } - } - - PHPUnit_Util_XML::removeCharacterDataNodes($expectedElement); - PHPUnit_Util_XML::removeCharacterDataNodes($actualElement); - - self::assertEquals( - $expectedElement->childNodes->length, - $actualElement->childNodes->length, - sprintf( - '%s%sNumber of child nodes of "%s" differs', - $message, - !empty($message) ? "\n" : '', - $expectedElement->tagName - ) - ); - - for ($i = 0; $i < $expectedElement->childNodes->length; $i++) { - self::assertEqualXMLStructure( - $expectedElement->childNodes->item($i), - $actualElement->childNodes->item($i), - $checkAttributes, - $message - ); - } - } - - /** - * Assert the presence, absence, or count of elements in a document matching - * the CSS $selector, regardless of the contents of those elements. - * - * The first argument, $selector, is the CSS selector used to match - * the elements in the $actual document. - * - * The second argument, $count, can be either boolean or numeric. - * When boolean, it asserts for presence of elements matching the selector - * (TRUE) or absence of elements (FALSE). - * When numeric, it asserts the count of elements. - * - * assertSelectCount("#binder", true, $xml); // any? - * assertSelectCount(".binder", 3, $xml); // exactly 3? - * - * @param array $selector - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = TRUE) - { - self::assertSelectEquals( - $selector, TRUE, $count, $actual, $message, $isHtml - ); - } - - /** - * assertSelectRegExp("#binder .name", "/Mike|Derek/", true, $xml); // any? - * assertSelectRegExp("#binder .name", "/Mike|Derek/", 3, $xml); // 3? - * - * @param array $selector - * @param string $pattern - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = TRUE) - { - self::assertSelectEquals( - $selector, "regexp:$pattern", $count, $actual, $message, $isHtml - ); - } - - /** - * assertSelectEquals("#binder .name", "Chuck", true, $xml); // any? - * assertSelectEquals("#binder .name", "Chuck", false, $xml); // none? - * - * @param array $selector - * @param string $content - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = TRUE) - { - $tags = PHPUnit_Util_XML::cssSelect( - $selector, $content, $actual, $isHtml - ); - - // assert specific number of elements - if (is_numeric($count)) { - $counted = $tags ? count($tags) : 0; - self::assertEquals($count, $counted, $message); - } - - // assert any elements exist if true, assert no elements exist if false - else if (is_bool($count)) { - $any = count($tags) > 0 && $tags[0] instanceof DOMNode; - - if ($count) { - self::assertTrue($any, $message); - } else { - self::assertFalse($any, $message); - } - } - - // check for range number of elements - else if (is_array($count) && - (isset($count['>']) || isset($count['<']) || - isset($count['>=']) || isset($count['<=']))) { - $counted = $tags ? count($tags) : 0; - - if (isset($count['>'])) { - self::assertTrue($counted > $count['>'], $message); - } - - if (isset($count['>='])) { - self::assertTrue($counted >= $count['>='], $message); - } - - if (isset($count['<'])) { - self::assertTrue($counted < $count['<'], $message); - } - - if (isset($count['<='])) { - self::assertTrue($counted <= $count['<='], $message); - } - } else { - throw new PHPUnit_Framework_Exception; - } - } - - /** - * Evaluate an HTML or XML string and assert its structure and/or contents. - * - * The first argument ($matcher) is an associative array that specifies the - * match criteria for the assertion: - * - * - `id` : the node with the given id attribute must match the - * corresponsing value. - * - `tag` : the node type must match the corresponding value. - * - `attributes` : a hash. The node's attributres must match the - * corresponsing values in the hash. - * - `content` : The text content must match the given value. - * - `parent` : a hash. The node's parent must match the - * corresponsing hash. - * - `child` : a hash. At least one of the node's immediate children - * must meet the criteria described by the hash. - * - `ancestor` : a hash. At least one of the node's ancestors must - * meet the criteria described by the hash. - * - `descendant` : a hash. At least one of the node's descendants must - * meet the criteria described by the hash. - * - `children` : a hash, for counting children of a node. - * Accepts the keys: - * - `count` : a number which must equal the number of children - * that match - * - `less_than` : the number of matching children must be greater - * than this number - * - `greater_than` : the number of matching children must be less than - * this number - * - `only` : another hash consisting of the keys to use to match - * on the children, and only matching children will be - * counted - * - * - * // Matcher that asserts that there is an element with an id="my_id". - * $matcher = array('id' => 'my_id'); - * - * // Matcher that asserts that there is a "span" tag. - * $matcher = array('tag' => 'span'); - * - * // Matcher that asserts that there is a "span" tag with the content - * // "Hello World". - * $matcher = array('tag' => 'span', 'content' => 'Hello World'); - * - * // Matcher that asserts that there is a "span" tag with content matching - * // the regular expression pattern. - * $matcher = array('tag' => 'span', 'content' => 'regexp:/Try P(HP|ython)/'); - * - * // Matcher that asserts that there is a "span" with an "list" class - * // attribute. - * $matcher = array( - * 'tag' => 'span', - * 'attributes' => array('class' => 'list') - * ); - * - * // Matcher that asserts that there is a "span" inside of a "div". - * $matcher = array( - * 'tag' => 'span', - * 'parent' => array('tag' => 'div') - * ); - * - * // Matcher that asserts that there is a "span" somewhere inside a - * // "table". - * $matcher = array( - * 'tag' => 'span', - * 'ancestor' => array('tag' => 'table') - * ); - * - * // Matcher that asserts that there is a "span" with at least one "em" - * // child. - * $matcher = array( - * 'tag' => 'span', - * 'child' => array('tag' => 'em') - * ); - * - * // Matcher that asserts that there is a "span" containing a (possibly - * // nested) "strong" tag. - * $matcher = array( - * 'tag' => 'span', - * 'descendant' => array('tag' => 'strong') - * ); - * - * // Matcher that asserts that there is a "span" containing 5-10 "em" tags - * // as immediate children. - * $matcher = array( - * 'tag' => 'span', - * 'children' => array( - * 'less_than' => 11, - * 'greater_than' => 4, - * 'only' => array('tag' => 'em') - * ) - * ); - * - * // Matcher that asserts that there is a "div", with an "ul" ancestor and - * // a "li" parent (with class="enum"), and containing a "span" descendant - * // that contains an element with id="my_test" and the text "Hello World". - * $matcher = array( - * 'tag' => 'div', - * 'ancestor' => array('tag' => 'ul'), - * 'parent' => array( - * 'tag' => 'li', - * 'attributes' => array('class' => 'enum') - * ), - * 'descendant' => array( - * 'tag' => 'span', - * 'child' => array( - * 'id' => 'my_test', - * 'content' => 'Hello World' - * ) - * ) - * ); - * - * // Use assertTag() to apply a $matcher to a piece of $html. - * $this->assertTag($matcher, $html); - * - * // Use assertTag() to apply a $matcher to a piece of $xml. - * $this->assertTag($matcher, $xml, '', FALSE); - * - * - * The second argument ($actual) is a string containing either HTML or - * XML text to be tested. - * - * The third argument ($message) is an optional message that will be - * used if the assertion fails. - * - * The fourth argument ($html) is an optional flag specifying whether - * to load the $actual string into a DOMDocument using the HTML or - * XML load strategy. It is TRUE by default, which assumes the HTML - * load strategy. In many cases, this will be acceptable for XML as well. - * - * @param array $matcher - * @param string $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertTag($matcher, $actual, $message = '', $isHtml = TRUE) - { - $dom = PHPUnit_Util_XML::load($actual, $isHtml); - $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); - $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; - - self::assertTrue($matched, $message); - } - - /** - * This assertion is the exact opposite of assertTag(). - * - * Rather than asserting that $matcher results in a match, it asserts that - * $matcher does not match. - * - * @param array $matcher - * @param string $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertNotTag($matcher, $actual, $message = '', $isHtml = TRUE) - { - $dom = PHPUnit_Util_XML::load($actual, $isHtml); - $tags = PHPUnit_Util_XML::findNodes($dom, $matcher, $isHtml); - $matched = count($tags) > 0 && $tags[0] instanceof DOMNode; - - self::assertFalse($matched, $message); - } - - /** - * Evaluates a PHPUnit_Framework_Constraint matcher object. - * - * @param mixed $value - * @param PHPUnit_Framework_Constraint $constraint - * @param string $message - * @since Method available since Release 3.0.0 - */ - public static function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '') - { - self::$count += count($constraint); - - $constraint->evaluate($value, $message); - } - - /** - * Asserts that two given JSON encoded objects or arrays are equal. - * - * @param string $expectedJson - * @param string $actualJson - * @param string $message - */ - public static function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '') - { - $expected = json_decode($expectedJson); - if ($jsonError = json_last_error()) { - $message .= - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - $jsonError, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('expected') - ); - } - - $actual = json_decode($actualJson); - if ($jsonError = json_last_error()) { - $message .= - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - $jsonError, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('actual') - ); - } - return self::assertEquals($expected, $actual, $message); - } - - /** - * Asserts that two given JSON encoded objects or arrays are not equal. - * - * @param string $expectedJson - * @param string $actualJson - * @param string $message - */ - public static function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '') - { - $expected = json_decode($expectedJson); - if ($jsonError = json_last_error()) { - $message .= - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - $jsonError, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('expected') - ); - } - - $actual = json_decode($actualJson); - if ($jsonError = json_last_error()) { - $message .= - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - $jsonError, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix('actual') - ); - } - - self::assertNotEquals($expected, $actual, $message); - } - - /** - * Asserts that the generated JSON encoded object and the content of the given file are equal. - * - * @param string $expectedFile - * @param string $actualJson - * @param string $message - */ - public static function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '') - { - self::assertFileExists($expectedFile, $message); - - if (!is_string($actualJson)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - // call constraint - $constraint = new PHPUnit_Framework_Constraint_JsonMatches( - file_get_contents($expectedFile) - ); - - self::assertThat($actualJson, $constraint, $message); - } - - /** - * Asserts that the generated JSON encoded object and the content of the given file are not equal. - * - * @param string $expectedFile - * @param string $actualJson - * @param string $message - */ - public static function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '') - { - self::assertFileExists($expectedFile, $message); - - if (!is_string($actualJson)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - // call constraint - $constraint = new PHPUnit_Framework_Constraint_JsonMatches( - file_get_contents($expectedFile) - ); - - self::assertThat($actualJson, new PHPUnit_Framework_Constraint_Not($constraint), $message); - } - - /** - * Asserts that two JSON files are not equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - */ - public static function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message = '') - { - self::assertFileExists($expectedFile, $message); - self::assertFileExists($actualFile, $message); - - $actualJson = file_get_contents($actualFile); - $expectedJson = file_get_contents($expectedFile); - - // call constraint - $constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches( - file_get_contents($expectedFile) - ); - - $constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson); - - self::assertThat($expectedJson, new PHPUnit_Framework_Constraint_Not($constraintActual), $message); - self::assertThat($actualJson, new PHPUnit_Framework_Constraint_Not($constraintExpected), $message); - } - - /** - * Asserts that two JSON files are equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - */ - public static function assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message = '') - { - self::assertFileExists($expectedFile, $message); - self::assertFileExists($actualFile, $message); - - $actualJson = file_get_contents($actualFile); - $expectedJson = file_get_contents($expectedFile); - - // call constraint - $constraintExpected = new PHPUnit_Framework_Constraint_JsonMatches( - file_get_contents($expectedFile) - ); - - $constraintActual = new PHPUnit_Framework_Constraint_JsonMatches($actualJson); - - self::assertThat($expectedJson, $constraintActual, $message); - self::assertThat($actualJson, $constraintExpected, $message); - } - - /** - * Returns a PHPUnit_Framework_Constraint_And matcher object. - * - * @return PHPUnit_Framework_Constraint_And - * @since Method available since Release 3.0.0 - */ - public static function logicalAnd() - { - $constraints = func_get_args(); - - $constraint = new PHPUnit_Framework_Constraint_And; - $constraint->setConstraints($constraints); - - return $constraint; - } - - /** - * Returns a PHPUnit_Framework_Constraint_Or matcher object. - * - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.0.0 - */ - public static function logicalOr() - { - $constraints = func_get_args(); - - $constraint = new PHPUnit_Framework_Constraint_Or; - $constraint->setConstraints($constraints); - - return $constraint; - } - - /** - * Returns a PHPUnit_Framework_Constraint_Not matcher object. - * - * @param PHPUnit_Framework_Constraint $constraint - * @return PHPUnit_Framework_Constraint_Not - * @since Method available since Release 3.0.0 - */ - public static function logicalNot(PHPUnit_Framework_Constraint $constraint) - { - return new PHPUnit_Framework_Constraint_Not($constraint); - } - - /** - * Returns a PHPUnit_Framework_Constraint_Xor matcher object. - * - * @return PHPUnit_Framework_Constraint_Xor - * @since Method available since Release 3.0.0 - */ - public static function logicalXor() - { - $constraints = func_get_args(); - - $constraint = new PHPUnit_Framework_Constraint_Xor; - $constraint->setConstraints($constraints); - - return $constraint; - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsAnything matcher object. - * - * @return PHPUnit_Framework_Constraint_IsAnything - * @since Method available since Release 3.0.0 - */ - public static function anything() - { - return new PHPUnit_Framework_Constraint_IsAnything; - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsTrue matcher object. - * - * @return PHPUnit_Framework_Constraint_IsTrue - * @since Method available since Release 3.3.0 - */ - public static function isTrue() - { - return new PHPUnit_Framework_Constraint_IsTrue; - } - - /** - * Returns a PHPUnit_Framework_Constraint_Callback matcher object. - * - * @param callable $callback - * @return PHPUnit_Framework_Constraint_Callback - */ - public static function callback($callback) - { - return new PHPUnit_Framework_Constraint_Callback($callback); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsFalse matcher object. - * - * @return PHPUnit_Framework_Constraint_IsFalse - * @since Method available since Release 3.3.0 - */ - public static function isFalse() - { - return new PHPUnit_Framework_Constraint_IsFalse; - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsNull matcher object. - * - * @return PHPUnit_Framework_Constraint_IsNull - * @since Method available since Release 3.3.0 - */ - public static function isNull() - { - return new PHPUnit_Framework_Constraint_IsNull; - } - - /** - * Returns a PHPUnit_Framework_Constraint_Attribute matcher object. - * - * @param PHPUnit_Framework_Constraint $constraint - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_Attribute - * @since Method available since Release 3.1.0 - */ - public static function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName) - { - return new PHPUnit_Framework_Constraint_Attribute( - $constraint, $attributeName - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_TraversableContains matcher - * object. - * - * @param mixed $value - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @return PHPUnit_Framework_Constraint_TraversableContains - * @since Method available since Release 3.0.0 - */ - public static function contains($value, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - return new PHPUnit_Framework_Constraint_TraversableContains($value, $checkForObjectIdentity, $checkForNonObjectIdentity); - } - - /** - * Returns a PHPUnit_Framework_Constraint_TraversableContainsOnly matcher - * object. - * - * @param string $type - * @return PHPUnit_Framework_Constraint_TraversableContainsOnly - * @since Method available since Release 3.1.4 - */ - public static function containsOnly($type) - { - return new PHPUnit_Framework_Constraint_TraversableContainsOnly($type); - } - - /** - * Returns a PHPUnit_Framework_Constraint_TraversableContainsOnly matcher - * object. - * - * @param string $classname - * @return PHPUnit_Framework_Constraint_TraversableContainsOnly - */ - public static function containsOnlyInstancesOf($classname) - { - return new PHPUnit_Framework_Constraint_TraversableContainsOnly($classname, FALSE); - } - - /** - * Returns a PHPUnit_Framework_Constraint_ArrayHasKey matcher object. - * - * @param mixed $key - * @return PHPUnit_Framework_Constraint_ArrayHasKey - * @since Method available since Release 3.0.0 - */ - public static function arrayHasKey($key) - { - return new PHPUnit_Framework_Constraint_ArrayHasKey($key); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object. - * - * @param mixed $value - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @return PHPUnit_Framework_Constraint_IsEqual - * @since Method available since Release 3.0.0 - */ - public static function equalTo($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - return new PHPUnit_Framework_Constraint_IsEqual( - $value, $delta, $maxDepth, $canonicalize, $ignoreCase - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object - * that is wrapped in a PHPUnit_Framework_Constraint_Attribute matcher - * object. - * - * @param string $attributeName - * @param mixed $value - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @return PHPUnit_Framework_Constraint_Attribute - * @since Method available since Release 3.1.0 - */ - public static function attributeEqualTo($attributeName, $value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - return self::attribute( - self::equalTo( - $value, $delta, $maxDepth, $canonicalize, $ignoreCase - ), - $attributeName - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsEmpty matcher object. - * - * @return PHPUnit_Framework_Constraint_IsEmpty - * @since Method available since Release 3.5.0 - */ - public static function isEmpty() - { - return new PHPUnit_Framework_Constraint_IsEmpty; - } - /** - * Returns a PHPUnit_Framework_Constraint_FileExists matcher object. - * - * @return PHPUnit_Framework_Constraint_FileExists - * @since Method available since Release 3.0.0 - */ - public static function fileExists() - { - return new PHPUnit_Framework_Constraint_FileExists; - } - - /** - * Returns a PHPUnit_Framework_Constraint_GreaterThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_GreaterThan - * @since Method available since Release 3.0.0 - */ - public static function greaterThan($value) - { - return new PHPUnit_Framework_Constraint_GreaterThan($value); - } - - /** - * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps - * a PHPUnit_Framework_Constraint_IsEqual and a - * PHPUnit_Framework_Constraint_GreaterThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.1.0 - */ - public static function greaterThanOrEqual($value) - { - return self::logicalOr( - new PHPUnit_Framework_Constraint_IsEqual($value), - new PHPUnit_Framework_Constraint_GreaterThan($value) - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_ClassHasAttribute matcher object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ClassHasAttribute - * @since Method available since Release 3.1.0 - */ - public static function classHasAttribute($attributeName) - { - return new PHPUnit_Framework_Constraint_ClassHasAttribute( - $attributeName - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_ClassHasStaticAttribute matcher - * object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @since Method available since Release 3.1.0 - */ - public static function classHasStaticAttribute($attributeName) - { - return new PHPUnit_Framework_Constraint_ClassHasStaticAttribute( - $attributeName - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_ObjectHasAttribute matcher object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ObjectHasAttribute - * @since Method available since Release 3.0.0 - */ - public static function objectHasAttribute($attributeName) - { - return new PHPUnit_Framework_Constraint_ObjectHasAttribute( - $attributeName - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsIdentical matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_IsIdentical - * @since Method available since Release 3.0.0 - */ - public static function identicalTo($value) - { - return new PHPUnit_Framework_Constraint_IsIdentical($value); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsInstanceOf matcher object. - * - * @param string $className - * @return PHPUnit_Framework_Constraint_IsInstanceOf - * @since Method available since Release 3.0.0 - */ - public static function isInstanceOf($className) - { - return new PHPUnit_Framework_Constraint_IsInstanceOf($className); - } - - /** - * Returns a PHPUnit_Framework_Constraint_IsType matcher object. - * - * @param string $type - * @return PHPUnit_Framework_Constraint_IsType - * @since Method available since Release 3.0.0 - */ - public static function isType($type) - { - return new PHPUnit_Framework_Constraint_IsType($type); - } - - /** - * Returns a PHPUnit_Framework_Constraint_LessThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_LessThan - * @since Method available since Release 3.0.0 - */ - public static function lessThan($value) - { - return new PHPUnit_Framework_Constraint_LessThan($value); - } - - /** - * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps - * a PHPUnit_Framework_Constraint_IsEqual and a - * PHPUnit_Framework_Constraint_LessThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.1.0 - */ - public static function lessThanOrEqual($value) - { - return self::logicalOr( - new PHPUnit_Framework_Constraint_IsEqual($value), - new PHPUnit_Framework_Constraint_LessThan($value) - ); - } - - /** - * Returns a PHPUnit_Framework_Constraint_PCREMatch matcher object. - * - * @param string $pattern - * @return PHPUnit_Framework_Constraint_PCREMatch - * @since Method available since Release 3.0.0 - */ - public static function matchesRegularExpression($pattern) - { - return new PHPUnit_Framework_Constraint_PCREMatch($pattern); - } - - /** - * Returns a PHPUnit_Framework_Constraint_StringMatches matcher object. - * - * @param string $string - * @return PHPUnit_Framework_Constraint_StringMatches - * @since Method available since Release 3.5.0 - */ - public static function matches($string) - { - return new PHPUnit_Framework_Constraint_StringMatches($string); - } - - /** - * Returns a PHPUnit_Framework_Constraint_StringStartsWith matcher object. - * - * @param mixed $prefix - * @return PHPUnit_Framework_Constraint_StringStartsWith - * @since Method available since Release 3.4.0 - */ - public static function stringStartsWith($prefix) - { - return new PHPUnit_Framework_Constraint_StringStartsWith($prefix); - } - - /** - * Returns a PHPUnit_Framework_Constraint_StringContains matcher object. - * - * @param string $string - * @param boolean $case - * @return PHPUnit_Framework_Constraint_StringContains - * @since Method available since Release 3.0.0 - */ - public static function stringContains($string, $case = TRUE) - { - return new PHPUnit_Framework_Constraint_StringContains($string, $case); - } - - /** - * Returns a PHPUnit_Framework_Constraint_StringEndsWith matcher object. - * - * @param mixed $suffix - * @return PHPUnit_Framework_Constraint_StringEndsWith - * @since Method available since Release 3.4.0 - */ - public static function stringEndsWith($suffix) - { - return new PHPUnit_Framework_Constraint_StringEndsWith($suffix); - } - - /** - * Fails a test with the given message. - * - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ - public static function fail($message = '') - { - throw new PHPUnit_Framework_AssertionFailedError($message); - } - - /** - * Returns the value of an attribute of a class or an object. - * This also works for attributes that are declared protected or private. - * - * @param mixed $classOrObject - * @param string $attributeName - * @return mixed - * @throws PHPUnit_Framework_Exception - */ - public static function readAttribute($classOrObject, $attributeName) - { - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name'); - } - - if (is_string($classOrObject)) { - if (!class_exists($classOrObject)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'class name' - ); - } - - return self::getStaticAttribute( - $classOrObject, - $attributeName - ); - } - - else if (is_object($classOrObject)) { - return self::getObjectAttribute( - $classOrObject, - $attributeName - ); - } - - else { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'class name or object' - ); - } - } - - /** - * Mark the test as incomplete. - * - * @param string $message - * @throws PHPUnit_Framework_IncompleteTestError - * @since Method available since Release 3.0.0 - */ - public static function markTestIncomplete($message = '') - { - throw new PHPUnit_Framework_IncompleteTestError($message); - } - - /** - * Mark the test as skipped. - * - * @param string $message - * @throws PHPUnit_Framework_SkippedTestError - * @since Method available since Release 3.0.0 - */ - public static function markTestSkipped($message = '') - { - throw new PHPUnit_Framework_SkippedTestError($message); - } - - /** - * Return the current assertion count. - * - * @return integer - * @since Method available since Release 3.3.3 - */ - public static function getCount() - { - return self::$count; - } - - /** - * Reset the assertion counter. - * - * @since Method available since Release 3.3.3 - */ - public static function resetCount() - { - self::$count = 0; - } - - /** - * Returns the value of a static attribute. - * This also works for attributes that are declared protected or private. - * - * @param string $className - * @param string $attributeName - * @return mixed - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.8.0 - */ - protected static function getStaticAttribute($className, $attributeName) - { - if (!is_string($className)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (!class_exists($className)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'class name'); - } - - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name'); - } - - $class = new ReflectionClass($className); - - while ($class) { - $attributes = $class->getStaticProperties(); - - if (array_key_exists($attributeName, $attributes)) { - return $attributes[$attributeName]; - } - - $class = $class->getParentClass(); - } - - throw new PHPUnit_Framework_Exception( - sprintf( - 'Attribute "%s" not found in class.', - - $attributeName - ) - ); - } - - /** - * Returns the value of an object's attribute. - * This also works for attributes that are declared protected or private. - * - * @param object $object - * @param string $attributeName - * @return mixed - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.8.0 - */ - protected static function getObjectAttribute($object, $attributeName) - { - if (!is_object($object)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'object'); - } - - if (!is_string($attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'string'); - } - - if(!preg_match('/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/', $attributeName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'valid attribute name'); - } - - try { - $attribute = new ReflectionProperty($object, $attributeName); - } - - catch (ReflectionException $e) { - $reflector = new ReflectionObject($object); - - while ($reflector = $reflector->getParentClass()) { - try { - $attribute = $reflector->getProperty($attributeName); - break; - } - - catch(ReflectionException $e) { - } - } - } - - if (isset($attribute)) { - if (!$attribute || $attribute->isPublic()) { - return $object->$attributeName; - } - - $attribute->setAccessible(TRUE); - $value = $attribute->getValue($object); - $attribute->setAccessible(FALSE); - - return $value; - } - - throw new PHPUnit_Framework_Exception( - sprintf( - 'Attribute "%s" not found in object.', - $attributeName - ) - ); - } -} diff --git a/PHPUnit/Framework/Assert/Functions.php b/PHPUnit/Framework/Assert/Functions.php deleted file mode 100644 index f86003a1f94..00000000000 --- a/PHPUnit/Framework/Assert/Functions.php +++ /dev/null @@ -1,1978 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -/** - * Returns a matcher that matches when the method it is evaluated for - * is executed zero or more times. - * - * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount - * @since Method available since Release 3.0.0 - */ -function any() -{ - return PHPUnit_Framework_TestCase::any(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsAnything matcher object. - * - * @return PHPUnit_Framework_Constraint_IsAnything - * @since Method available since Release 3.0.0 - */ -function anything() -{ - return PHPUnit_Framework_Assert::anything(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_ArrayHasKey matcher object. - * - * @param mixed $key - * @return PHPUnit_Framework_Constraint_ArrayHasKey - * @since Method available since Release 3.0.0 - */ -function arrayHasKey($key) -{ - return PHPUnit_Framework_Assert::arrayHasKey($key); -} - -/** - * Asserts that an array has a specified key. - * - * @param mixed $key - * @param array $array - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertArrayHasKey($key, array $array, $message = '') -{ - return PHPUnit_Framework_Assert::assertArrayHasKey($key, $array, $message); -} - -/** - * Asserts that an array does not have a specified key. - * - * @param mixed $key - * @param array $array - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertArrayNotHasKey($key, array $array, $message = '') -{ - return PHPUnit_Framework_Assert::assertArrayNotHasKey($key, $array, $message); -} - -/** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object contains a needle. - * - * @param mixed $needle - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 3.0.0 - */ -function assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) -{ - return PHPUnit_Framework_Assert::assertAttributeContains($needle, $haystackAttributeName, $haystackClassOrObject, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); -} - -/** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object contains only values of a given type. - * - * @param string $type - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ -function assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType, $message); -} - -/** - * Asserts the number of elements of an array, Countable or Iterator - * that is stored in an attribute. - * - * @param integer $expectedCount - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.6.0 - */ -function assertAttributeCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message); -} - -/** - * Asserts that a static attribute of a class or an attribute of an object - * is empty. - * - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeEmpty($haystackAttributeName, $haystackClassOrObject, $message); -} - -/** - * Asserts that a variable is equal to an attribute of an object. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ -function assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertAttributeEquals($expected, $actualAttributeName, $actualClassOrObject, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Asserts that an attribute is greater than another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeGreaterThan($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that an attribute is greater than or equal to another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeGreaterThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeInstanceOf($expected, $attributeName, $classOrObject, $message); -} - -/** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeInternalType($expected, $attributeName, $classOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeInternalType($expected, $attributeName, $classOrObject, $message); -} - -/** - * Asserts that an attribute is smaller than another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeLessThan($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that an attribute is smaller than or equal to another value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeLessThanOrEqual($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object does not contain a needle. - * - * @param mixed $needle - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 3.0.0 - */ -function assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) -{ - return PHPUnit_Framework_Assert::assertAttributeNotContains($needle, $haystackAttributeName, $haystackClassOrObject, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); -} - -/** - * Asserts that a haystack that is stored in a static attribute of a class - * or an attribute of an object does not contain only values of a given - * type. - * - * @param string $type - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ -function assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType = NULL, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotContainsOnly($type, $haystackAttributeName, $haystackClassOrObject, $isNativeType, $message); -} - -/** - * Asserts the number of elements of an array, Countable or Iterator - * that is stored in an attribute. - * - * @param integer $expectedCount - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.6.0 - */ -function assertAttributeNotCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotCount($expectedCount, $haystackAttributeName, $haystackClassOrObject, $message); -} - -/** - * Asserts that a static attribute of a class or an attribute of an object - * is not empty. - * - * @param string $haystackAttributeName - * @param mixed $haystackClassOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotEmpty($haystackAttributeName, $haystackClassOrObject, $message); -} - -/** - * Asserts that a variable is not equal to an attribute of an object. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param string $actualClassOrObject - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ -function assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertAttributeNotEquals($expected, $actualAttributeName, $actualClassOrObject, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotInstanceOf($expected, $attributeName, $classOrObject, $message); -} - -/** - * Asserts that an attribute is of a given type. - * - * @param string $expected - * @param string $attributeName - * @param mixed $classOrObject - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotInternalType($expected, $attributeName, $classOrObject, $message); -} - -/** - * Asserts that a variable and an attribute of an object do not have the - * same type and value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param object $actualClassOrObject - * @param string $message - */ -function assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeNotSame($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that a variable and an attribute of an object have the same type - * and value. - * - * @param mixed $expected - * @param string $actualAttributeName - * @param object $actualClassOrObject - * @param string $message - */ -function assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message = '') -{ - return PHPUnit_Framework_Assert::assertAttributeSame($expected, $actualAttributeName, $actualClassOrObject, $message); -} - -/** - * Asserts that a class has a specified attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertClassHasAttribute($attributeName, $className, $message = '') -{ - return PHPUnit_Framework_Assert::assertClassHasAttribute($attributeName, $className, $message); -} - -/** - * Asserts that a class has a specified static attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertClassHasStaticAttribute($attributeName, $className, $message = '') -{ - return PHPUnit_Framework_Assert::assertClassHasStaticAttribute($attributeName, $className, $message); -} - -/** - * Asserts that a class does not have a specified attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertClassNotHasAttribute($attributeName, $className, $message = '') -{ - return PHPUnit_Framework_Assert::assertClassNotHasAttribute($attributeName, $className, $message); -} - -/** - * Asserts that a class does not have a specified static attribute. - * - * @param string $attributeName - * @param string $className - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertClassNotHasStaticAttribute($attributeName, $className, $message = '') -{ - return PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute($attributeName, $className, $message); -} - -/** - * Asserts that a haystack contains a needle. - * - * @param mixed $needle - * @param mixed $haystack - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 2.1.0 - */ -function assertContains($needle, $haystack, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) -{ - return PHPUnit_Framework_Assert::assertContains($needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); -} - -/** - * Asserts that a haystack contains only values of a given type. - * - * @param string $type - * @param mixed $haystack - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ -function assertContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') -{ - return PHPUnit_Framework_Assert::assertContainsOnly($type, $haystack, $isNativeType, $message); -} - -/** - * Asserts the number of elements of an array, Countable or Iterator. - * - * @param integer $expectedCount - * @param mixed $haystack - * @param string $message - */ -function assertCount($expectedCount, $haystack, $message = '') -{ - return PHPUnit_Framework_Assert::assertCount($expectedCount, $haystack, $message); -} - -/** - * Asserts that a variable is empty. - * - * @param mixed $actual - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ -function assertEmpty($actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertEmpty($actual, $message); -} - -/** - * Asserts that a hierarchy of DOMElements matches. - * - * @param DOMElement $expectedElement - * @param DOMElement $actualElement - * @param boolean $checkAttributes - * @param string $message - * @author Mattis Stordalen Flister - * @since Method available since Release 3.3.0 - */ -function assertEqualXMLStructure(DOMElement $expectedElement, DOMElement $actualElement, $checkAttributes = FALSE, $message = '') -{ - return PHPUnit_Framework_Assert::assertEqualXMLStructure($expectedElement, $actualElement, $checkAttributes, $message); -} - -/** - * Asserts that two variables are equal. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ -function assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a condition is false. - * - * @param boolean $condition - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ -function assertFalse($condition, $message = '') -{ - return PHPUnit_Framework_Assert::assertFalse($condition, $message); -} - -/** - * Asserts that the contents of one file is equal to the contents of another - * file. - * - * @param string $expected - * @param string $actual - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.2.14 - */ -function assertFileEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertFileEquals($expected, $actual, $message, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a file exists. - * - * @param string $filename - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertFileExists($filename, $message = '') -{ - return PHPUnit_Framework_Assert::assertFileExists($filename, $message); -} - -/** - * Asserts that the contents of one file is not equal to the contents of - * another file. - * - * @param string $expected - * @param string $actual - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.2.14 - */ -function assertFileNotEquals($expected, $actual, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertFileNotEquals($expected, $actual, $message, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a file does not exist. - * - * @param string $filename - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertFileNotExists($filename, $message = '') -{ - return PHPUnit_Framework_Assert::assertFileNotExists($filename, $message); -} - -/** - * Asserts that a value is greater than another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertGreaterThan($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertGreaterThan($expected, $actual, $message); -} - -/** - * Asserts that a value is greater than or equal to another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertGreaterThanOrEqual($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertGreaterThanOrEqual($expected, $actual, $message); -} - -/** - * Asserts that a variable is of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertInstanceOf($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertInstanceOf($expected, $actual, $message); -} - -/** - * Asserts that a variable is of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertInternalType($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertInternalType($expected, $actual, $message); -} - -/** - * Asserts that two given JSON encoded objects or arrays are equal. - * - * @param string $expectedJson - * @param string $actualJson - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonStringEqualsJsonString($expectedJson, $actualJson, $message); -} - -/** - * Asserts that two given JSON encoded objects or arrays are not equal. - * - * @param string $expectedJson - * @param string $actualJson - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonString($expectedJson, $actualJson, $message); -} - -/** - * Asserts that the generated JSON encoded object and the content of the given file are equal. - * - * @param string $expectedFile - * @param string $actualJson - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonStringEqualsJsonFile($expectedFile, $actualJson, $message); -} - -/** - * Asserts that the generated JSON encoded object and the content of the given file are not equal. - * - * @param string $expectedFile - * @param string $actualJson - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonFile($expectedFile, $actualJson, $message); -} - -/** - * Asserts that two JSON files are not equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonFileNotEqualsJsonFile($expectedFile, $actualFile, $message); -} - -/** - * Asserts that two JSON files are equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.7.0 - */ -function assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message = '') -{ - return PHPUnit_Framework_Assert::assertJsonFileEqualsJsonFile($expectedFile, $actualFile, $message); -} - -/** - * Asserts that a value is smaller than another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertLessThan($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertLessThan($expected, $actual, $message); -} - -/** - * Asserts that a value is smaller than or equal to another value. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertLessThanOrEqual($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertLessThanOrEqual($expected, $actual, $message); -} - -/** - * Asserts that a haystack does not contain a needle. - * - * @param mixed $needle - * @param mixed $haystack - * @param string $message - * @param boolean $ignoreCase - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @since Method available since Release 2.1.0 - */ -function assertNotContains($needle, $haystack, $message = '', $ignoreCase = FALSE, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) -{ - return PHPUnit_Framework_Assert::assertNotContains($needle, $haystack, $message, $ignoreCase, $checkForObjectIdentity, $checkForNonObjectIdentity); -} - -/** - * Asserts that a haystack does not contain only values of a given type. - * - * @param string $type - * @param mixed $haystack - * @param boolean $isNativeType - * @param string $message - * @since Method available since Release 3.1.4 - */ -function assertNotContainsOnly($type, $haystack, $isNativeType = NULL, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotContainsOnly($type, $haystack, $isNativeType, $message); -} - -/** - * Asserts the number of elements of an array, Countable or Iterator. - * - * @param integer $expectedCount - * @param mixed $haystack - * @param string $message - */ -function assertNotCount($expectedCount, $haystack, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotCount($expectedCount, $haystack, $message); -} - -/** - * Asserts that a variable is not empty. - * - * @param mixed $actual - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ -function assertNotEmpty($actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotEmpty($actual, $message); -} - -/** - * Asserts that two variables are not equal. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 2.3.0 - */ -function assertNotEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertNotEquals($expected, $actual, $message, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a variable is not of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertNotInstanceOf($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotInstanceOf($expected, $actual, $message); -} - -/** - * Asserts that a variable is not of a given type. - * - * @param string $expected - * @param mixed $actual - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertNotInternalType($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotInternalType($expected, $actual, $message); -} - -/** - * Asserts that a variable is not NULL. - * - * @param mixed $actual - * @param string $message - */ -function assertNotNull($actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotNull($actual, $message); -} - -/** - * Asserts that a string does not match a given regular expression. - * - * @param string $pattern - * @param string $string - * @param string $message - * @since Method available since Release 2.1.0 - */ -function assertNotRegExp($pattern, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotRegExp($pattern, $string, $message); -} - -/** - * Asserts that two variables do not have the same type and value. - * Used on objects, it asserts that two variables do not reference - * the same object. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - */ -function assertNotSame($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotSame($expected, $actual, $message); -} - -/** - * Assert that the size of two arrays (or `Countable` or `Iterator` objects) - * is not the same. - * - * @param integer $expected - * @param mixed $actual - * @param string $message - */ -function assertNotSameSize($expectedCount, $haystack, $message = '') -{ - return PHPUnit_Framework_Assert::assertNotSameSize($expectedCount, $haystack, $message); -} - -/** - * This assertion is the exact opposite of assertTag(). - * - * Rather than asserting that $matcher results in a match, it asserts that - * $matcher does not match. - * - * @param array $matcher - * @param string $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ -function assertNotTag($matcher, $actual, $message = '', $isHtml = TRUE) -{ - return PHPUnit_Framework_Assert::assertNotTag($matcher, $actual, $message, $isHtml); -} - -/** - * Asserts that a variable is NULL. - * - * @param mixed $actual - * @param string $message - */ -function assertNull($actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertNull($actual, $message); -} - -/** - * Asserts that an object has a specified attribute. - * - * @param string $attributeName - * @param object $object - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertObjectHasAttribute($attributeName, $object, $message = '') -{ - return PHPUnit_Framework_Assert::assertObjectHasAttribute($attributeName, $object, $message); -} - -/** - * Asserts that an object does not have a specified attribute. - * - * @param string $attributeName - * @param object $object - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertObjectNotHasAttribute($attributeName, $object, $message = '') -{ - return PHPUnit_Framework_Assert::assertObjectNotHasAttribute($attributeName, $object, $message); -} - -/** - * Asserts that a string matches a given regular expression. - * - * @param string $pattern - * @param string $string - * @param string $message - */ -function assertRegExp($pattern, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertRegExp($pattern, $string, $message); -} - -/** - * Asserts that two variables have the same type and value. - * Used on objects, it asserts that two variables reference - * the same object. - * - * @param mixed $expected - * @param mixed $actual - * @param string $message - */ -function assertSame($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertSame($expected, $actual, $message); -} - -/** - * Assert that the size of two arrays (or `Countable` or `Iterator` objects) - * is the same. - * - * @param integer $expected - * @param mixed $actual - * @param string $message - */ -function assertSameSize($expected, $actual, $message = '') -{ - return PHPUnit_Framework_Assert::assertSameSize($expected, $actual, $message); -} - -/** - * Assert the presence, absence, or count of elements in a document matching - * the CSS $selector, regardless of the contents of those elements. - * - * The first argument, $selector, is the CSS selector used to match - * the elements in the $actual document. - * - * The second argument, $count, can be either boolean or numeric. - * When boolean, it asserts for presence of elements matching the selector - * (TRUE) or absence of elements (FALSE). - * When numeric, it asserts the count of elements. - * - * assertSelectCount("#binder", true, $xml); // any? - * assertSelectCount(".binder", 3, $xml); // exactly 3? - * - * @param array $selector - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ -function assertSelectCount($selector, $count, $actual, $message = '', $isHtml = TRUE) -{ - return PHPUnit_Framework_Assert::assertSelectCount($selector, $count, $actual, $message, $isHtml); -} - -/** - * assertSelectEquals("#binder .name", "Chuck", true, $xml); // any? - * assertSelectEquals("#binder .name", "Chuck", false, $xml); // none? - * - * @param array $selector - * @param string $content - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ -function assertSelectEquals($selector, $content, $count, $actual, $message = '', $isHtml = TRUE) -{ - return PHPUnit_Framework_Assert::assertSelectEquals($selector, $content, $count, $actual, $message, $isHtml); -} - -/** - * assertSelectRegExp("#binder .name", "/Mike|Derek/", true, $xml); // any? - * assertSelectRegExp("#binder .name", "/Mike|Derek/", 3, $xml);// 3? - * - * @param array $selector - * @param string $pattern - * @param integer $count - * @param mixed $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ -function assertSelectRegExp($selector, $pattern, $count, $actual, $message = '', $isHtml = TRUE) -{ - return PHPUnit_Framework_Assert::assertSelectRegExp($selector, $pattern, $count, $actual, $message, $isHtml); -} - -/** - * Asserts that a string ends not with a given prefix. - * - * @param string $suffix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ -function assertStringEndsNotWith($suffix, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringEndsNotWith($suffix, $string, $message); -} - -/** - * Asserts that a string ends with a given prefix. - * - * @param string $suffix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ -function assertStringEndsWith($suffix, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringEndsWith($suffix, $string, $message); -} - -/** - * Asserts that the contents of a string is equal - * to the contents of a file. - * - * @param string $expectedFile - * @param string $actualString - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.3.0 - */ -function assertStringEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertStringEqualsFile($expectedFile, $actualString, $message, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a string matches a given format string. - * - * @param string $format - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertStringMatchesFormat($format, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringMatchesFormat($format, $string, $message); -} - -/** - * Asserts that a string matches a given format file. - * - * @param string $formatFile - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertStringMatchesFormatFile($formatFile, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringMatchesFormatFile($formatFile, $string, $message); -} - -/** - * Asserts that the contents of a string is not equal - * to the contents of a file. - * - * @param string $expectedFile - * @param string $actualString - * @param string $message - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @since Method available since Release 3.3.0 - */ -function assertStringNotEqualsFile($expectedFile, $actualString, $message = '', $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::assertStringNotEqualsFile($expectedFile, $actualString, $message, $canonicalize, $ignoreCase); -} - -/** - * Asserts that a string does not match a given format string. - * - * @param string $format - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertStringNotMatchesFormat($format, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringNotMatchesFormat($format, $string, $message); -} - -/** - * Asserts that a string does not match a given format string. - * - * @param string $formatFile - * @param string $string - * @param string $message - * @since Method available since Release 3.5.0 - */ -function assertStringNotMatchesFormatFile($formatFile, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringNotMatchesFormatFile($formatFile, $string, $message); -} - -/** - * Asserts that a string starts not with a given prefix. - * - * @param string $prefix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ -function assertStringStartsNotWith($prefix, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringStartsNotWith($prefix, $string, $message); -} - -/** - * Asserts that a string starts with a given prefix. - * - * @param string $prefix - * @param string $string - * @param string $message - * @since Method available since Release 3.4.0 - */ -function assertStringStartsWith($prefix, $string, $message = '') -{ - return PHPUnit_Framework_Assert::assertStringStartsWith($prefix, $string, $message); -} - -/** - * Evaluate an HTML or XML string and assert its structure and/or contents. - * - * The first argument ($matcher) is an associative array that specifies the - * match criteria for the assertion: - * - * - `id` : the node with the given id attribute must match the - * corresponsing value. - * - `tag` : the node type must match the corresponding value. - * - `attributes` : a hash. The node's attributres must match the - * corresponsing values in the hash. - * - `content` : The text content must match the given value. - * - `parent` : a hash. The node's parent must match the - * corresponsing hash. - * - `child`: a hash. At least one of the node's immediate children - * must meet the criteria described by the hash. - * - `ancestor` : a hash. At least one of the node's ancestors must - * meet the criteria described by the hash. - * - `descendant` : a hash. At least one of the node's descendants must - * meet the criteria described by the hash. - * - `children` : a hash, for counting children of a node. - * Accepts the keys: - *- `count`: a number which must equal the number of children - * that match - *- `less_than`: the number of matching children must be greater - * than this number - *- `greater_than` : the number of matching children must be less than - * this number - *- `only` : another hash consisting of the keys to use to match - * on the children, and only matching children will be - * counted - * - * - * // Matcher that asserts that there is an element with an id="my_id". - * $matcher = array('id' => 'my_id'); - * - * // Matcher that asserts that there is a "span" tag. - * $matcher = array('tag' => 'span'); - * - * // Matcher that asserts that there is a "span" tag with the content - * // "Hello World". - * $matcher = array('tag' => 'span', 'content' => 'Hello World'); - * - * // Matcher that asserts that there is a "span" tag with content matching - * // the regular expression pattern. - * $matcher = array('tag' => 'span', 'content' => 'regexp:/Try P(HP|ython)/'); - * - * // Matcher that asserts that there is a "span" with an "list" class - * // attribute. - * $matcher = array( - * 'tag'=> 'span', - * 'attributes' => array('class' => 'list') - * ); - * - * // Matcher that asserts that there is a "span" inside of a "div". - * $matcher = array( - * 'tag'=> 'span', - * 'parent' => array('tag' => 'div') - * ); - * - * // Matcher that asserts that there is a "span" somewhere inside a - * // "table". - * $matcher = array( - * 'tag' => 'span', - * 'ancestor' => array('tag' => 'table') - * ); - * - * // Matcher that asserts that there is a "span" with at least one "em" - * // child. - * $matcher = array( - * 'tag' => 'span', - * 'child' => array('tag' => 'em') - * ); - * - * // Matcher that asserts that there is a "span" containing a (possibly - * // nested) "strong" tag. - * $matcher = array( - * 'tag'=> 'span', - * 'descendant' => array('tag' => 'strong') - * ); - * - * // Matcher that asserts that there is a "span" containing 5-10 "em" tags - * // as immediate children. - * $matcher = array( - * 'tag' => 'span', - * 'children' => array( - * 'less_than'=> 11, - * 'greater_than' => 4, - * 'only' => array('tag' => 'em') - * ) - * ); - * - * // Matcher that asserts that there is a "div", with an "ul" ancestor and - * // a "li" parent (with class="enum"), and containing a "span" descendant - * // that contains an element with id="my_test" and the text "Hello World". - * $matcher = array( - * 'tag'=> 'div', - * 'ancestor' => array('tag' => 'ul'), - * 'parent' => array( - * 'tag'=> 'li', - * 'attributes' => array('class' => 'enum') - * ), - * 'descendant' => array( - * 'tag' => 'span', - * 'child' => array( - * 'id' => 'my_test', - * 'content' => 'Hello World' - * ) - * ) - * ); - * - * // Use assertTag() to apply a $matcher to a piece of $html. - * $this->assertTag($matcher, $html); - * - * // Use assertTag() to apply a $matcher to a piece of $xml. - * $this->assertTag($matcher, $xml, '', FALSE); - * - * - * The second argument ($actual) is a string containing either HTML or - * XML text to be tested. - * - * The third argument ($message) is an optional message that will be - * used if the assertion fails. - * - * The fourth argument ($html) is an optional flag specifying whether - * to load the $actual string into a DOMDocument using the HTML or - * XML load strategy. It is TRUE by default, which assumes the HTML - * load strategy. In many cases, this will be acceptable for XML as well. - * - * @param array $matcher - * @param string $actual - * @param string $message - * @param boolean $isHtml - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ -function assertTag($matcher, $actual, $message = '', $isHtml = TRUE) -{ - return PHPUnit_Framework_Assert::assertTag($matcher, $actual, $message, $isHtml); -} - -/** - * Evaluates a PHPUnit_Framework_Constraint matcher object. - * - * @param mixed$value - * @param PHPUnit_Framework_Constraint $constraint - * @param string $message - * @since Method available since Release 3.0.0 - */ -function assertThat($value, PHPUnit_Framework_Constraint $constraint, $message = '') -{ - return PHPUnit_Framework_Assert::assertThat($value, $constraint, $message); -} - -/** - * Asserts that a condition is true. - * - * @param boolean $condition - * @param string $message - * @throws PHPUnit_Framework_AssertionFailedError - */ -function assertTrue($condition, $message = '') -{ - return PHPUnit_Framework_Assert::assertTrue($condition, $message); -} - -/** - * Asserts that two XML files are equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlFileEqualsXmlFile($expectedFile, $actualFile, $message); -} - -/** - * Asserts that two XML files are not equal. - * - * @param string $expectedFile - * @param string $actualFile - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlFileNotEqualsXmlFile($expectedFile, $actualFile, $message); -} - -/** - * Asserts that two XML documents are equal. - * - * @param string $expectedFile - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.3.0 - */ -function assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlStringEqualsXmlFile($expectedFile, $actualXml, $message); -} - -/** - * Asserts that two XML documents are equal. - * - * @param string $expectedXml - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlStringEqualsXmlString($expectedXml, $actualXml, $message); -} - -/** - * Asserts that two XML documents are not equal. - * - * @param string $expectedFile - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.3.0 - */ -function assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlFile($expectedFile, $actualXml, $message); -} - -/** - * Asserts that two XML documents are not equal. - * - * @param string $expectedXml - * @param string $actualXml - * @param string $message - * @since Method available since Release 3.1.0 - */ -function assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message = '') -{ - return PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlString($expectedXml, $actualXml, $message); -} - -/** - * Returns a matcher that matches when the method it is evaluated for - * is invoked at the given $index. - * - * @param integer $index - * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex - * @since Method available since Release 3.0.0 - */ -function at($index) -{ - return PHPUnit_Framework_TestCase::at($index); -} - -/** - * Returns a matcher that matches when the method it is evaluated for - * is executed at least once. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce - * @since Method available since Release 3.0.0 - */ -function atLeastOnce() -{ - return PHPUnit_Framework_TestCase::atLeastOnce(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Attribute matcher object. - * - * @param PHPUnit_Framework_Constraint $constraint - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_Attribute - * @since Method available since Release 3.1.0 - */ -function attribute(PHPUnit_Framework_Constraint $constraint, $attributeName) -{ - return PHPUnit_Framework_Assert::attribute($constraint, $attributeName); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object - * that is wrapped in a PHPUnit_Framework_Constraint_Attribute matcher - * object. - * - * @param string $attributeName - * @param mixed $value - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @return PHPUnit_Framework_Constraint_Attribute - * @since Method available since Release 3.1.0 - */ -function attributeEqualTo($attributeName, $value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::attributeEqualTo($attributeName, $value, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Returns a PHPUnit_Framework_Constraint_ClassHasAttribute matcher object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ClassHasAttribute - * @since Method available since Release 3.1.0 - */ -function classHasAttribute($attributeName) -{ - return PHPUnit_Framework_Assert::classHasAttribute($attributeName); -} - -/** - * Returns a PHPUnit_Framework_Constraint_ClassHasStaticAttribute matcher - * object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @since Method available since Release 3.1.0 - */ -function classHasStaticAttribute($attributeName) -{ - return PHPUnit_Framework_Assert::classHasStaticAttribute($attributeName); -} - -/** - * Returns a PHPUnit_Framework_Constraint_TraversableContains matcher - * object. - * - * @param mixed $value - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @return PHPUnit_Framework_Constraint_TraversableContains - * @since Method available since Release 3.0.0 - */ -function contains($value, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) -{ - return PHPUnit_Framework_Assert::contains($value, $checkForObjectIdentity, $checkForNonObjectIdentity); -} - -/** - * Returns a PHPUnit_Framework_Constraint_TraversableContainsOnly matcher - * object. - * - * @param string $type - * @return PHPUnit_Framework_Constraint_TraversableContainsOnly - * @since Method available since Release 3.1.4 - */ -function containsOnly($type) -{ - return PHPUnit_Framework_Assert::containsOnly($type); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsEqual matcher object. - * - * @param mixed $value - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - * @return PHPUnit_Framework_Constraint_IsEqual - * @since Method available since Release 3.0.0 - */ -function equalTo($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) -{ - return PHPUnit_Framework_Assert::equalTo($value, $delta, $maxDepth, $canonicalize, $ignoreCase); -} - -/** - * Returns a matcher that matches when the method it is evaluated for - * is executed exactly $count times. - * - * @param integer $count - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ -function exactly($count) -{ - return PHPUnit_Framework_TestCase::exactly($count); -} - -/** - * Returns a PHPUnit_Framework_Constraint_FileExists matcher object. - * - * @return PHPUnit_Framework_Constraint_FileExists - * @since Method available since Release 3.0.0 - */ -function fileExists() -{ - return PHPUnit_Framework_Assert::fileExists(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_GreaterThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_GreaterThan - * @since Method available since Release 3.0.0 - */ -function greaterThan($value) -{ - return PHPUnit_Framework_Assert::greaterThan($value); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps - * a PHPUnit_Framework_Constraint_IsEqual and a - * PHPUnit_Framework_Constraint_GreaterThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.1.0 - */ -function greaterThanOrEqual($value) -{ - return PHPUnit_Framework_Assert::greaterThanOrEqual($value); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsIdentical matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_IsIdentical - * @since Method available since Release 3.0.0 - */ -function identicalTo($value) -{ - return PHPUnit_Framework_Assert::identicalTo($value); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsEmpty matcher object. - * - * @return PHPUnit_Framework_Constraint_IsEmpty - * @since Method available since Release 3.5.0 - */ -function isEmpty() -{ - return PHPUnit_Framework_Assert::isEmpty(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsFalse matcher object. - * - * @return PHPUnit_Framework_Constraint_IsFalse - * @since Method available since Release 3.3.0 - */ -function isFalse() -{ - return PHPUnit_Framework_Assert::isFalse(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsInstanceOf matcher object. - * - * @param string $className - * @return PHPUnit_Framework_Constraint_IsInstanceOf - * @since Method available since Release 3.0.0 - */ -function isInstanceOf($className) -{ - return PHPUnit_Framework_Assert::isInstanceOf($className); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsNull matcher object. - * - * @return PHPUnit_Framework_Constraint_IsNull - * @since Method available since Release 3.3.0 - */ -function isNull() -{ - return PHPUnit_Framework_Assert::isNull(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsTrue matcher object. - * - * @return PHPUnit_Framework_Constraint_IsTrue - * @since Method available since Release 3.3.0 - */ -function isTrue() -{ - return PHPUnit_Framework_Assert::isTrue(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Callback matcher object. - * - * @param callable $callback - * @return PHPUnit_Framework_Constraint_Callback - */ -function callback($callback) -{ - return PHPUnit_Framework_Assert::callback($callback); -} - -/** - * Returns a PHPUnit_Framework_Constraint_IsType matcher object. - * - * @param string $type - * @return PHPUnit_Framework_Constraint_IsType - * @since Method available since Release 3.0.0 - */ -function isType($type) -{ - return PHPUnit_Framework_Assert::isType($type); -} - -/** - * Returns a PHPUnit_Framework_Constraint_LessThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_LessThan - * @since Method available since Release 3.0.0 - */ -function lessThan($value) -{ - return PHPUnit_Framework_Assert::lessThan($value); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Or matcher object that wraps - * a PHPUnit_Framework_Constraint_IsEqual and a - * PHPUnit_Framework_Constraint_LessThan matcher object. - * - * @param mixed $value - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.1.0 - */ -function lessThanOrEqual($value) -{ - return PHPUnit_Framework_Assert::lessThanOrEqual($value); -} - -/** - * Returns a PHPUnit_Framework_Constraint_And matcher object. - * - * @return PHPUnit_Framework_Constraint_And - * @since Method available since Release 3.0.0 - */ -function logicalAnd() -{ - return PHPUnit_Framework_Assert::logicalAnd(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Not matcher object. - * - * @param PHPUnit_Framework_Constraint $constraint - * @return PHPUnit_Framework_Constraint_Not - * @since Method available since Release 3.0.0 - */ -function logicalNot(PHPUnit_Framework_Constraint $constraint) -{ - return PHPUnit_Framework_Assert::logicalNot($constraint); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Or matcher object. - * - * @return PHPUnit_Framework_Constraint_Or - * @since Method available since Release 3.0.0 - */ -function logicalOr() -{ - return PHPUnit_Framework_Assert::logicalOr(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_Xor matcher object. - * - * @return PHPUnit_Framework_Constraint_Xor - * @since Method available since Release 3.0.0 - */ -function logicalXor() -{ - return PHPUnit_Framework_Assert::logicalXor(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_StringMatches matcher object. - * - * @param string $string - * @return PHPUnit_Framework_Constraint_StringMatches - * @since Method available since Release 3.5.0 - */ -function matches($string) -{ - return PHPUnit_Framework_Assert::matches($string); -} - -/** - * Returns a PHPUnit_Framework_Constraint_PCREMatch matcher object. - * - * @param string $pattern - * @return PHPUnit_Framework_Constraint_PCREMatch - * @since Method available since Release 3.0.0 - */ -function matchesRegularExpression($pattern) -{ - return PHPUnit_Framework_Assert::matchesRegularExpression($pattern); -} - -/** - * Returns a matcher that matches when the method it is evaluated for - * is never executed. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ -function never() -{ - return PHPUnit_Framework_TestCase::never(); -} - -/** - * Returns a PHPUnit_Framework_Constraint_ObjectHasAttribute matcher object. - * - * @param string $attributeName - * @return PHPUnit_Framework_Constraint_ObjectHasAttribute - * @since Method available since Release 3.0.0 - */ -function objectHasAttribute($attributeName) -{ - return PHPUnit_Framework_Assert::objectHasAttribute($attributeName); -} - -/** - * - * - * @param mixed $value, ... - * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls - * @since Method available since Release 3.0.0 - */ -function onConsecutiveCalls() -{ - return PHPUnit_Framework_TestCase::onConsecutiveCalls(); -} - -/** - * Returns a matcher that matches when the method it is evaluated for - * is executed exactly once. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ -function once() -{ - return PHPUnit_Framework_TestCase::once(); -} - -/** - * - * - * @param integer $argumentIndex - * @return PHPUnit_Framework_MockObject_Stub_ReturnArgument - * @since Method available since Release 3.3.0 - */ -function returnArgument($argumentIndex) -{ - return PHPUnit_Framework_TestCase::returnArgument($argumentIndex); -} - -/** - * - * - * @param mixed $callback - * @return PHPUnit_Framework_MockObject_Stub_ReturnCallback - * @since Method available since Release 3.3.0 - */ -function returnCallback($callback) -{ - return PHPUnit_Framework_TestCase::returnCallback($callback); -} - -/** - * Returns the current object. - * - * This method is useful when mocking a fluent interface. - * - * @return PHPUnit_Framework_MockObject_Stub_ReturnSelf - * @since Method available since Release 3.6.0 - */ -function returnSelf() -{ - return PHPUnit_Framework_TestCase::returnSelf(); -} - -/** - * - * - * @param mixed $value - * @return PHPUnit_Framework_MockObject_Stub_Return - * @since Method available since Release 3.0.0 - */ -function returnValue($value) -{ - return PHPUnit_Framework_TestCase::returnValue($value); -} - -/** - * - * - * @param array $valueMap - * @return PHPUnit_Framework_MockObject_Stub_ReturnValueMap - * @since Method available since Release 3.6.0 - */ -function returnValueMap(array $valueMap) -{ - return PHPUnit_Framework_TestCase::returnValueMap($valueMap); -} - -/** - * Returns a PHPUnit_Framework_Constraint_StringContains matcher object. - * - * @param string $string - * @param boolean $case - * @return PHPUnit_Framework_Constraint_StringContains - * @since Method available since Release 3.0.0 - */ -function stringContains($string, $case = TRUE) -{ - return PHPUnit_Framework_Assert::stringContains($string, $case); -} - -/** - * Returns a PHPUnit_Framework_Constraint_StringEndsWith matcher object. - * - * @param mixed $suffix - * @return PHPUnit_Framework_Constraint_StringEndsWith - * @since Method available since Release 3.4.0 - */ -function stringEndsWith($suffix) -{ - return PHPUnit_Framework_Assert::stringEndsWith($suffix); -} - -/** - * Returns a PHPUnit_Framework_Constraint_StringStartsWith matcher object. - * - * @param mixed $prefix - * @return PHPUnit_Framework_Constraint_StringStartsWith - * @since Method available since Release 3.4.0 - */ -function stringStartsWith($prefix) -{ - return PHPUnit_Framework_Assert::stringStartsWith($prefix); -} - -/** - * - * - * @param Exception $exception - * @return PHPUnit_Framework_MockObject_Stub_Exception - * @since Method available since Release 3.1.0 - */ -function throwException(Exception $exception) -{ - return PHPUnit_Framework_TestCase::throwException($exception); -} diff --git a/PHPUnit/Framework/AssertionFailedError.php b/PHPUnit/Framework/AssertionFailedError.php deleted file mode 100644 index 77728e029e7..00000000000 --- a/PHPUnit/Framework/AssertionFailedError.php +++ /dev/null @@ -1,68 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Thrown when an assertion failed. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_AssertionFailedError extends PHPUnit_Framework_Exception implements PHPUnit_Framework_SelfDescribing -{ - /** - * Wrapper for getMessage() which is declared as final. - * - * @return string - */ - public function toString() - { - return $this->getMessage(); - } -} diff --git a/PHPUnit/Framework/BaseTestListener.php b/PHPUnit/Framework/BaseTestListener.php deleted file mode 100644 index 60cf2ccf536..00000000000 --- a/PHPUnit/Framework/BaseTestListener.php +++ /dev/null @@ -1,76 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Giorgio Sironi - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * An empty Listener that can be extended to implement TestListener - * with just a few lines of code. - * @see PHPUnit_Framework_TestListener for documentation on the API methods. - * - * @package PHPUnit - * @subpackage Framework - * @author Giorgio Sironi - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -abstract class PHPUnit_Framework_BaseTestListener implements PHPUnit_Framework_TestListener -{ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) {} - - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) {} - - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) {} - - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) {} - - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) {} - - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) {} - - public function startTest(PHPUnit_Framework_Test $test) {} - - public function endTest(PHPUnit_Framework_Test $test, $time) {} -} diff --git a/PHPUnit/Framework/Comparator.php b/PHPUnit/Framework/Comparator.php deleted file mode 100644 index 4a233f0fa68..00000000000 --- a/PHPUnit/Framework/Comparator.php +++ /dev/null @@ -1,106 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -use SebastianBergmann\Exporter\Exporter; - -/** - * Abstract base class for comparators which compare values for equality. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -abstract class PHPUnit_Framework_Comparator -{ - /** - * @var PHPUnit_Framework_ComparatorFactory - */ - protected $factory; - - protected $exporter; - - public function __construct() - { - $this->exporter = new Exporter; - } - - /** - * @param PHPUnit_Framework_ComparatorFactory $factory - */ - public function setFactory(PHPUnit_Framework_ComparatorFactory $factory) - { - $this->factory = $factory; - } - - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - abstract public function accepts($expected, $actual); - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - abstract public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE); -} diff --git a/PHPUnit/Framework/Comparator/Array.php b/PHPUnit/Framework/Comparator/Array.php deleted file mode 100644 index e784055c109..00000000000 --- a/PHPUnit/Framework/Comparator/Array.php +++ /dev/null @@ -1,177 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares arrays for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Array extends PHPUnit_Framework_Comparator -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return is_array($expected) && is_array($actual); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE, array &$processed = array()) - { - if ($canonicalize) { - sort($expected); - sort($actual); - } - - $remaining = $actual; - $expString = $actString = "Array (\n"; - $equal = TRUE; - - foreach ($expected as $key => $value) { - unset($remaining[$key]); - - if (!array_key_exists($key, $actual)) { - $expString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $this->exporter->shortenedExport($value) - ); - $equal = FALSE; - continue; - } - - try { - $this->factory->getComparatorFor($value, $actual[$key])->assertEquals($value, $actual[$key], $delta, $canonicalize, $ignoreCase, $processed); - $expString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $this->exporter->shortenedExport($value) - ); - $actString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $this->exporter->shortenedExport($actual[$key]) - ); - } - - catch (PHPUnit_Framework_ComparisonFailure $e) { - $expString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $e->getExpectedAsString() - ? $this->indent($e->getExpectedAsString()) - : $this->exporter->shortenedExport($e->getExpected()) - ); - $actString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $e->getActualAsString() - ? $this->indent($e->getActualAsString()) - : $this->exporter->shortenedExport($e->getActual()) - ); - $equal = FALSE; - } - } - - foreach ($remaining as $key => $value) { - $actString .= sprintf( - " %s => %s\n", - - $this->exporter->export($key), - $this->exporter->shortenedExport($value) - ); - $equal = FALSE; - } - - $expString .= ')'; - $actString .= ')'; - - if (!$equal) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $expString, - $actString, - FALSE, - 'Failed asserting that two arrays are equal.' - ); - } - } - - protected function indent($lines) - { - return trim(str_replace("\n", "\n ", $lines)); - } -} diff --git a/PHPUnit/Framework/Comparator/DOMDocument.php b/PHPUnit/Framework/Comparator/DOMDocument.php deleted file mode 100644 index 620834a94c3..00000000000 --- a/PHPUnit/Framework/Comparator/DOMDocument.php +++ /dev/null @@ -1,114 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares DOMDocument instances for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_DOMDocument extends PHPUnit_Framework_Comparator_Object -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return $expected instanceof DOMDocument && $actual instanceof DOMDocument; - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - if ($expected->C14N() !== $actual->C14N()) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->domToText($expected), - $this->domToText($actual), - FALSE, - 'Failed asserting that two DOM documents are equal.' - ); - } - } - - /** - * Returns the normalized, whitespace-cleaned, and indented textual - * representation of a DOMDocument. - * - * @param DOMDocument $document - * @return string - */ - protected function domToText(DOMDocument $document) - { - $document->formatOutput = TRUE; - $document->normalizeDocument(); - - return $document->saveXML(); - } -} diff --git a/PHPUnit/Framework/Comparator/Double.php b/PHPUnit/Framework/Comparator/Double.php deleted file mode 100644 index 6c1f406000b..00000000000 --- a/PHPUnit/Framework/Comparator/Double.php +++ /dev/null @@ -1,101 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares doubles for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Double extends PHPUnit_Framework_Comparator_Numeric -{ - /** - * Smallest value available in PHP. - * - * @var float - */ - const EPSILON = 0.0000000001; - - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return (is_double($expected) || is_double($actual)) && is_numeric($expected) && is_numeric($actual); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - if ($delta == 0) { - $delta = self::EPSILON; - } - - parent::assertEquals($expected, $actual, $delta, $canonicalize, $ignoreCase); - } -} diff --git a/PHPUnit/Framework/Comparator/Exception.php b/PHPUnit/Framework/Comparator/Exception.php deleted file mode 100644 index 0315495307d..00000000000 --- a/PHPUnit/Framework/Comparator/Exception.php +++ /dev/null @@ -1,92 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares Exception instances for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Exception extends PHPUnit_Framework_Comparator_Object -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return $expected instanceof Exception && $actual instanceof Exception; - } - - /** - * Converts an object to an array containing all of its private, protected - * and public properties. - * - * @param object $object - * @return array - */ - protected function toArray($object) - { - $array = parent::toArray($object); - - unset( - $array['file'], - $array['line'], - $array['trace'], - $array['string'], // some internal property of Exception - $array['xdebug_message'] // some internal property added by XDebug - ); - - return $array; - } -} diff --git a/PHPUnit/Framework/Comparator/MockObject.php b/PHPUnit/Framework/Comparator/MockObject.php deleted file mode 100644 index 4ae8bdf8420..00000000000 --- a/PHPUnit/Framework/Comparator/MockObject.php +++ /dev/null @@ -1,86 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares PHPUnit_Framework_MockObject_MockObject instances for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_MockObject extends PHPUnit_Framework_Comparator_Object -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return $expected instanceof PHPUnit_Framework_MockObject_MockObject && $actual instanceof PHPUnit_Framework_MockObject_MockObject; - } - - /** - * Converts an object to an array containing all of its private, protected - * and public properties. - * - * @param object $object - * @return array - */ - protected function toArray($object) - { - $array = parent::toArray($object); - - unset($array['__phpunit_invocationMocker']); - - return $array; - } -} diff --git a/PHPUnit/Framework/Comparator/Numeric.php b/PHPUnit/Framework/Comparator/Numeric.php deleted file mode 100644 index 18bc99d3375..00000000000 --- a/PHPUnit/Framework/Comparator/Numeric.php +++ /dev/null @@ -1,112 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares numerical values for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @author Alexander - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Numeric extends PHPUnit_Framework_Comparator_Scalar -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - // all numerical values, but not if one of them is a double - return is_numeric($expected) && is_numeric($actual) && !(is_double($expected) || is_double($actual)); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - if (is_infinite($actual) && is_infinite($expected)) { - return; - } - - if ((is_infinite($actual) XOR is_infinite($expected)) || - (is_nan($actual) OR is_nan($expected)) || - abs($actual - $expected) > $delta) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - '', - '', - FALSE, - sprintf( - 'Failed asserting that %s matches expected %s.', - - $this->exporter->export($actual), - $this->exporter->export($expected) - ) - ); - } - } -} diff --git a/PHPUnit/Framework/Comparator/Object.php b/PHPUnit/Framework/Comparator/Object.php deleted file mode 100644 index 32cc24ac8fe..00000000000 --- a/PHPUnit/Framework/Comparator/Object.php +++ /dev/null @@ -1,140 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares objects for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Object extends PHPUnit_Framework_Comparator_Array -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return is_object($expected) && is_object($actual); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE, array &$processed = array()) - { - if (get_class($actual) !== get_class($expected)) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->exporter->export($expected), - $this->exporter->export($actual), - FALSE, - sprintf( - '%s is not instance of expected class "%s".', - - $this->exporter->export($actual), - get_class($expected) - ) - ); - } - - // don't compare twice to allow for cyclic dependencies - if (in_array(array($actual, $expected), $processed, TRUE) || - in_array(array($expected, $actual), $processed, TRUE)) { - return; - } - - $processed[] = array($actual, $expected); - - // don't compare objects if they are identical - // this helps to avoid the error "maximum function nesting level reached" - // CAUTION: this conditional clause is not tested - if ($actual !== $expected) { - try { - parent::assertEquals( - $this->exporter->toArray($expected), - $this->exporter->toArray($actual), - $delta, - $canonicalize, - $ignoreCase, - $processed - ); - } - - catch (PHPUnit_Framework_ComparisonFailure $e) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - // replace "Array" with "MyClass object" - substr_replace($e->getExpectedAsString(), get_class($expected) . ' Object', 0, 5), - substr_replace($e->getActualAsString(), get_class($actual) . ' Object', 0, 5), - FALSE, - 'Failed asserting that two objects are equal.' - ); - } - } - } -} diff --git a/PHPUnit/Framework/Comparator/Resource.php b/PHPUnit/Framework/Comparator/Resource.php deleted file mode 100644 index 898c472f2dc..00000000000 --- a/PHPUnit/Framework/Comparator/Resource.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares resources for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Resource extends PHPUnit_Framework_Comparator -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return is_resource($expected) && is_resource($actual); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - if ($actual != $expected) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->exporter->export($expected), - $this->exporter->export($actual) - ); - } - } -} diff --git a/PHPUnit/Framework/Comparator/Scalar.php b/PHPUnit/Framework/Comparator/Scalar.php deleted file mode 100644 index 37cb3552d46..00000000000 --- a/PHPUnit/Framework/Comparator/Scalar.php +++ /dev/null @@ -1,136 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares scalar or NULL values for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Scalar extends PHPUnit_Framework_Comparator -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - * @since Method available since Release 3.6.0 - */ - public function accepts($expected, $actual) - { - return ((is_scalar($expected) XOR NULL === $expected) && - (is_scalar($actual) XOR NULL === $actual)) - // allow comparison between strings and objects featuring __toString() - || (is_string($expected) && is_object($actual) && method_exists($actual, '__toString')) - || (is_object($expected) && method_exists($expected, '__toString') && is_string($actual)); - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - $expectedToCompare = $expected; - $actualToCompare = $actual; - - // always compare as strings to avoid strange behaviour - // otherwise 0 == 'Foobar' - if (is_string($expected) || is_string($actual)) { - $expectedToCompare = (string)$expectedToCompare; - $actualToCompare = (string)$actualToCompare; - - if ($ignoreCase) { - $expectedToCompare = strtolower($expectedToCompare); - $actualToCompare = strtolower($actualToCompare); - } - } - - if ($expectedToCompare != $actualToCompare) { - if (is_string($expected) && is_string($actual)) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->exporter->export($expected), - $this->exporter->export($actual), - FALSE, - 'Failed asserting that two strings are equal.' - ); - } - - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - // no diff is required - '', - '', - FALSE, - sprintf( - 'Failed asserting that %s matches expected %s.', - - $this->exporter->export($actual), - $this->exporter->export($expected) - ) - ); - } - } -} diff --git a/PHPUnit/Framework/Comparator/SplObjectStorage.php b/PHPUnit/Framework/Comparator/SplObjectStorage.php deleted file mode 100644 index 790deb6f98e..00000000000 --- a/PHPUnit/Framework/Comparator/SplObjectStorage.php +++ /dev/null @@ -1,114 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares SplObjectStorage instances for equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_SplObjectStorage extends PHPUnit_Framework_Comparator -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return $expected instanceof SplObjectStorage && $actual instanceof SplObjectStorage; - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - foreach ($actual as $object) { - if (!$expected->contains($object)) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->exporter->export($expected), - $this->exporter->export($actual), - FALSE, - 'Failed asserting that two objects are equal.' - ); - } - } - - foreach ($expected as $object) { - if (!$actual->contains($object)) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - $this->exporter->export($expected), - $this->exporter->export($actual), - FALSE, - 'Failed asserting that two objects are equal.' - ); - } - } - } -} diff --git a/PHPUnit/Framework/Comparator/Type.php b/PHPUnit/Framework/Comparator/Type.php deleted file mode 100644 index bbd99d78657..00000000000 --- a/PHPUnit/Framework/Comparator/Type.php +++ /dev/null @@ -1,105 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Compares values for type equality. - * - * @package PHPUnit - * @subpackage Framework_Comparator - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Comparator_Type extends PHPUnit_Framework_Comparator -{ - /** - * Returns whether the comparator can compare two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return boolean - */ - public function accepts($expected, $actual) - { - return TRUE; - } - - /** - * Asserts that two values are equal. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @param float $delta The allowed numerical distance between two values to - * consider them equal - * @param bool $canonicalize If set to TRUE, arrays are sorted before - * comparison - * @param bool $ignoreCase If set to TRUE, upper- and lowercasing is - * ignored when comparing string values - * @throws PHPUnit_Framework_ComparisonFailure Thrown when the comparison - * fails. Contains information about the - * specific errors that lead to the failure. - */ - public function assertEquals($expected, $actual, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - if (gettype($expected) != gettype($actual)) { - throw new PHPUnit_Framework_ComparisonFailure( - $expected, - $actual, - // we don't need a diff - '', - '', - FALSE, - sprintf( - '%s does not match expected type "%s".', - - $this->exporter->shortenedExport($actual), - gettype($expected) - ) - ); - } - } -} diff --git a/PHPUnit/Framework/ComparatorFactory.php b/PHPUnit/Framework/ComparatorFactory.php deleted file mode 100644 index 2aa7be5cf16..00000000000 --- a/PHPUnit/Framework/ComparatorFactory.php +++ /dev/null @@ -1,156 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Factory for comparators which compare values for equality. - * - * @package PHPUnit - * @subpackage Framework - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_ComparatorFactory -{ - /** - * @var array - */ - protected $comparators = array(); - - /** - * @var PHPUnit_Framework_ComparatorFactory - */ - private static $defaultInstance = NULL; - - /** - * Constructs a new factory. - */ - public function __construct() - { - $this->register(new PHPUnit_Framework_Comparator_Type); - $this->register(new PHPUnit_Framework_Comparator_Scalar); - $this->register(new PHPUnit_Framework_Comparator_Numeric); - $this->register(new PHPUnit_Framework_Comparator_Double); - $this->register(new PHPUnit_Framework_Comparator_Array); - $this->register(new PHPUnit_Framework_Comparator_Resource); - $this->register(new PHPUnit_Framework_Comparator_Object); - $this->register(new PHPUnit_Framework_Comparator_Exception); - $this->register(new PHPUnit_Framework_Comparator_SplObjectStorage); - $this->register(new PHPUnit_Framework_Comparator_DOMDocument); - $this->register(new PHPUnit_Framework_Comparator_MockObject); - } - - /** - * Returns the default instance. - * - * @return PHPUnit_Framework_ComparatorFactory - */ - public static function getDefaultInstance() - { - if (self::$defaultInstance === NULL) { - self::$defaultInstance = new PHPUnit_Framework_ComparatorFactory; - } - - return self::$defaultInstance; - } - - /** - * Returns the correct comparator for comparing two values. - * - * @param mixed $expected The first value to compare - * @param mixed $actual The second value to compare - * @return PHPUnit_Framework_Comparator - * @throws PHPUnit_Framework_Exception - */ - public function getComparatorFor($expected, $actual) - { - foreach ($this->comparators as $comparator) { - if ($comparator->accepts($expected, $actual)) { - return $comparator; - } - } - - throw new PHPUnit_Framework_Exception( - sprintf( - 'No comparator is registered for comparing the types "%s" and "%s"', - gettype($expected), gettype($actual) - ) - ); - } - - /** - * Registers a new comparator. - * - * This comparator will be returned by getInstance() if its accept() method - * returns TRUE for the compared values. It has higher priority than the - * existing comparators, meaning that its accept() method will be tested - * before those of the other comparators. - * - * @param PHPUnit_Framework_Comparator $comparator The registered comparator - */ - public function register(PHPUnit_Framework_Comparator $comparator) - { - array_unshift($this->comparators, $comparator); - $comparator->setFactory($this); - } - - /** - * Unregisters a comparator. - * - * This comparator will no longer be returned by getInstance(). - * - * @param PHPUnit_Framework_Comparator $comparator The unregistered comparator - */ - public function unregister(PHPUnit_Framework_Comparator $comparator) - { - foreach ($this->comparators as $key => $_comparator) { - if ($comparator === $_comparator) { - unset($this->comparators[$key]); - } - } - } -} diff --git a/PHPUnit/Framework/ComparisonFailure.php b/PHPUnit/Framework/ComparisonFailure.php deleted file mode 100644 index 6ab85b7a2f0..00000000000 --- a/PHPUnit/Framework/ComparisonFailure.php +++ /dev/null @@ -1,172 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -use SebastianBergmann\Diff; - -/** - * Thrown when an assertion for string equality failed. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_ComparisonFailure extends PHPUnit_Framework_AssertionFailedError -{ - /** - * Expected value of the retrieval which does not match $actual. - * @var mixed - */ - protected $expected; - - /** - * Actually retrieved value which does not match $expected. - * @var mixed - */ - protected $actual; - - /** - * The string representation of the expected value - * @var string - */ - protected $expectedAsString; - - /** - * The string representation of the actual value - * @var string - */ - protected $actualAsString; - - /** - * @var boolean - */ - protected $identical; - - /** - * Optional message which is placed in front of the first line - * returned by toString(). - * @var string - */ - protected $message; - - /** - * Initialises with the expected value and the actual value. - * - * @param mixed $expected Expected value retrieved. - * @param mixed $actual Actual value retrieved. - * @param string $expectedAsString - * @param string $actualAsString - * @param boolean $identical - * @param string $message A string which is prefixed on all returned lines - * in the difference output. - */ - public function __construct($expected, $actual, $expectedAsString, $actualAsString, $identical = FALSE, $message = '') - { - $this->expected = $expected; - $this->actual = $actual; - $this->expectedAsString = $expectedAsString; - $this->actualAsString = $actualAsString; - $this->message = $message; - } - - /** - * @return mixed - */ - public function getActual() - { - return $this->actual; - } - - /** - * @return mixed - */ - public function getExpected() - { - return $this->expected; - } - - /** - * @return string - */ - public function getActualAsString() - { - return $this->actualAsString; - } - - /** - * @return string - */ - public function getExpectedAsString() - { - return $this->expectedAsString; - } - - /** - * @return string - */ - public function getDiff() - { - if (!$this->actualAsString && !$this->expectedAsString) { - return ''; - } - - $diff = new Diff("--- Expected\n+++ Actual\n"); - - return $diff->diff($this->expectedAsString, $this->actualAsString); - } - - /** - * @return string - */ - public function toString() - { - return $this->message . $this->getDiff(); - } -} diff --git a/PHPUnit/Framework/Constraint.php b/PHPUnit/Framework/Constraint.php deleted file mode 100644 index 536b3f0ca44..00000000000 --- a/PHPUnit/Framework/Constraint.php +++ /dev/null @@ -1,188 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -use SebastianBergmann\Exporter\Exporter; - -/** - * Abstract base class for constraints. which are placed upon any value. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 3.0.0 - */ -abstract class PHPUnit_Framework_Constraint implements Countable, PHPUnit_Framework_SelfDescribing -{ - protected $exporter; - - public function __construct() - { - $this->exporter = new Exporter; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = FALSE; - - if ($this->matches($other)) { - $success = TRUE; - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * This method can be overridden to implement the evaluation algorithm. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return FALSE; - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.4.0 - */ - public function count() - { - return 1; - } - - /** - * Throws an exception for the given compared value and test description - * - * @param mixed $other Evaluated value or object. - * @param string $description Additional information about the test - * @param PHPUnit_Framework_ComparisonFailure $comparisonFailure - * @throws PHPUnit_Framework_ExpectationFailedException - */ - protected function fail($other, $description, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL) - { - $failureDescription = sprintf( - 'Failed asserting that %s.', - $this->failureDescription($other) - ); - - $additionalFailureDescription = $this->additionalFailureDescription($other); - if ($additionalFailureDescription) { - $failureDescription .= "\n" . $additionalFailureDescription; - } - - if (!empty($description)) { - $failureDescription = $description . "\n" . $failureDescription; - } - - throw new PHPUnit_Framework_ExpectationFailedException( - $failureDescription, - $comparisonFailure - ); - } - - /** - * Return additional failure description where needed - * - * The function can be overridden to provide additional failure - * information like a diff - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function additionalFailureDescription($other) - { - return ''; - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * To provide additional failure information additionalFailureDescription - * can be used. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return $this->exporter->export($other) . ' ' . $this->toString(); - } -} diff --git a/PHPUnit/Framework/Constraint/And.php b/PHPUnit/Framework/Constraint/And.php deleted file mode 100644 index 9597abcc5cb..00000000000 --- a/PHPUnit/Framework/Constraint/And.php +++ /dev/null @@ -1,164 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Logical AND. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_And extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint[] - */ - protected $constraints = array(); - - /** - * @var PHPUnit_Framework_Constraint - */ - protected $lastConstraint = NULL; - - /** - * @param PHPUnit_Framework_Constraint[] $constraints - * @throws PHPUnit_Framework_Exception - */ - public function setConstraints(array $constraints) - { - $this->constraints = array(); - - foreach ($constraints as $constraint) { - if (!($constraint instanceof PHPUnit_Framework_Constraint)) { - throw new PHPUnit_Framework_Exception( - 'All parameters to ' . __CLASS__ . - ' must be a constraint object.' - ); - } - - $this->constraints[] = $constraint; - } - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = TRUE; - $constraint = NULL; - - foreach ($this->constraints as $constraint) { - if (!$constraint->evaluate($other, $description, TRUE)) { - $success = FALSE; - break; - } - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - $text = ''; - - foreach ($this->constraints as $key => $constraint) { - if ($key > 0) { - $text .= ' and '; - } - - $text .= $constraint->toString(); - } - - return $text; - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.4.0 - */ - public function count() - { - $count = 0; - - foreach ($this->constraints as $constraint) { - $count += count($constraint); - } - - return $count; - } -} diff --git a/PHPUnit/Framework/Constraint/ArrayHasKey.php b/PHPUnit/Framework/Constraint/ArrayHasKey.php deleted file mode 100644 index da8a5e3643b..00000000000 --- a/PHPUnit/Framework/Constraint/ArrayHasKey.php +++ /dev/null @@ -1,115 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the array it is evaluated for has a given key. - * - * Uses array_key_exists() to check if the key is found in the input array, if - * not found the evaluaton fails. - * - * The array key is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_ArrayHasKey extends PHPUnit_Framework_Constraint -{ - /** - * @var integer|string - */ - protected $key; - - /** - * @param integer|string $key - */ - public function __construct($key) - { - parent::__construct(); - $this->key = $key; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return array_key_exists($this->key, $other); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'has the key ' . $this->exporter->export($this->key); - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return 'an array ' . $this->toString(); - } -} diff --git a/PHPUnit/Framework/Constraint/Attribute.php b/PHPUnit/Framework/Constraint/Attribute.php deleted file mode 100644 index fefcd2798f5..00000000000 --- a/PHPUnit/Framework/Constraint/Attribute.php +++ /dev/null @@ -1,129 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.0 - */ - -class PHPUnit_Framework_Constraint_Attribute extends PHPUnit_Framework_Constraint_Composite -{ - /** - * @var string - */ - protected $attributeName; - - /** - * @param PHPUnit_Framework_Constraint $constraint - * @param string $attributeName - */ - public function __construct(PHPUnit_Framework_Constraint $constraint, $attributeName) - { - parent::__construct($constraint); - - $this->attributeName = $attributeName; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - return parent::evaluate( - PHPUnit_Framework_Assert::readAttribute( - $other, $this->attributeName - ), - $description, - $returnResult - ); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'attribute "' . $this->attributeName . '" ' . - $this->innerConstraint->toString(); - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return $this->toString(); - } -} diff --git a/PHPUnit/Framework/Constraint/Callback.php b/PHPUnit/Framework/Constraint/Callback.php deleted file mode 100644 index d80f693a4ac..00000000000 --- a/PHPUnit/Framework/Constraint/Callback.php +++ /dev/null @@ -1,110 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - */ - -/** - * Constraint that evaluates against a specified closure. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Timon Rapp - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - */ -class PHPUnit_Framework_Constraint_Callback extends PHPUnit_Framework_Constraint -{ - private $callback; - - /** - * @param callable $callback - * @throws InvalidArgumentException - */ - public function __construct(callable $callback) - { - parent::__construct(); - - $this->callback = $callback; - } - - /** - * Evaluates the constraint for parameter $value. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $value Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return call_user_func($this->callback, $other); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is accepted by specified callback'; - } - - private function callbackToString($callback) - { - if (!is_array($callback)) { - return $callback; - } - if (empty($callback)) { - return "empty array"; - } - if (!isset($callback[0]) || !isset($callback[1])) { - return "array without indexes 0 and 1 set"; - } - if (is_object($callback[0])) { - $callback[0] = get_class($callback[0]); - } - return $callback[0] . '::' . $callback[1]; - } - -} diff --git a/PHPUnit/Framework/Constraint/ClassHasAttribute.php b/PHPUnit/Framework/Constraint/ClassHasAttribute.php deleted file mode 100644 index c3081d03586..00000000000 --- a/PHPUnit/Framework/Constraint/ClassHasAttribute.php +++ /dev/null @@ -1,125 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.0 - */ - -/** - * Constraint that asserts that the class it is evaluated for has a given - * attribute. - * - * The attribute name is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.0 - */ -class PHPUnit_Framework_Constraint_ClassHasAttribute extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $attributeName; - - /** - * @param string $attributeName - */ - public function __construct($attributeName) - { - parent::__construct(); - $this->attributeName = $attributeName; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - $class = new ReflectionClass($other); - - return $class->hasProperty($this->attributeName); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return sprintf( - 'has attribute "%s"', - - $this->attributeName - ); - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - '%sclass "%s" %s', - - is_object($other) ? 'object of ' : '', - is_object($other) ? get_class($other) : $other, - $this->toString() - ); - } -} diff --git a/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php b/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php deleted file mode 100644 index 2c57675760d..00000000000 --- a/PHPUnit/Framework/Constraint/ClassHasStaticAttribute.php +++ /dev/null @@ -1,98 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.0 - */ - -/** - * Constraint that asserts that the class it is evaluated for has a given - * static attribute. - * - * The attribute name is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.0 - */ -class PHPUnit_Framework_Constraint_ClassHasStaticAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - $class = new ReflectionClass($other); - - if ($class->hasProperty($this->attributeName)) { - $attribute = $class->getProperty($this->attributeName); - - return $attribute->isStatic(); - } else { - return FALSE; - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - * @since Method available since Release 3.3.0 - */ - public function toString() - { - return sprintf( - 'has static attribute "%s"', - - $this->attributeName - ); - } -} diff --git a/PHPUnit/Framework/Constraint/Composite.php b/PHPUnit/Framework/Constraint/Composite.php deleted file mode 100644 index 7749f177bbd..00000000000 --- a/PHPUnit/Framework/Constraint/Composite.php +++ /dev/null @@ -1,115 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ - -abstract class PHPUnit_Framework_Constraint_Composite extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint - */ - protected $innerConstraint; - - /** - * @param PHPUnit_Framework_Constraint $innerConstraint - * @param string $attributeName - */ - public function __construct(PHPUnit_Framework_Constraint $innerConstraint) - { - parent::__construct(); - $this->innerConstraint = $innerConstraint; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - try { - return $this->innerConstraint->evaluate( - $other, - $description, - $returnResult - ); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->fail($other, $description); - } - } - - /** - * Counts the number of constraint elements. - * - * @return integer - */ - public function count() - { - return count($this->innerConstraint); - } -} diff --git a/PHPUnit/Framework/Constraint/Count.php b/PHPUnit/Framework/Constraint/Count.php deleted file mode 100644 index d268f6b877a..00000000000 --- a/PHPUnit/Framework/Constraint/Count.php +++ /dev/null @@ -1,129 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Constraint_Count extends PHPUnit_Framework_Constraint -{ - /** - * @var integer - */ - protected $expectedCount = 0; - - /** - * @param integer $expected - */ - public function __construct($expected) - { - parent::__construct(); - $this->expectedCount = $expected; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other - * @return boolean - */ - protected function matches($other) - { - return $this->expectedCount === $this->getCountOf($other); - } - - /** - * @param mixed $other - * @return boolean - */ - protected function getCountOf($other) - { - if ($other instanceof Countable || is_array($other)) { - return count($other); - } - - else if ($other instanceof Iterator) { - return iterator_count($other); - } - } - - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - 'actual size %d matches expected size %d', - - $this->getCountOf($other), - $this->expectedCount - ); - } - - /** - * @return string - */ - public function toString() - { - return 'count matches '; - } -} diff --git a/PHPUnit/Framework/Constraint/Exception.php b/PHPUnit/Framework/Constraint/Exception.php deleted file mode 100644 index 510d7891bce..00000000000 --- a/PHPUnit/Framework/Constraint/Exception.php +++ /dev/null @@ -1,131 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.6 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.6 - */ -class PHPUnit_Framework_Constraint_Exception extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $className; - - /** - * @param string $className - */ - public function __construct($className) - { - parent::__construct(); - $this->className = $className; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $other instanceof $this->className; - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - if ($other !== NULL) { - $message = ''; - if ($other instanceof Exception) { - $message = '. Message was: "' . $other->getMessage() . '" at' - . "\n" . $other->getTraceAsString(); - } - return sprintf( - 'exception of type "%s" matches expected exception "%s"%s', - - get_class($other), - $this->className, - $message - ); - } - - return sprintf( - 'exception of type "%s" is thrown', - - $this->className - ); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return sprintf( - 'exception of type "%s"', - - $this->className - ); - } -} diff --git a/PHPUnit/Framework/Constraint/ExceptionCode.php b/PHPUnit/Framework/Constraint/ExceptionCode.php deleted file mode 100644 index dc9aa1a2fa6..00000000000 --- a/PHPUnit/Framework/Constraint/ExceptionCode.php +++ /dev/null @@ -1,110 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.6 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.6 - */ -class PHPUnit_Framework_Constraint_ExceptionCode extends PHPUnit_Framework_Constraint -{ - /** - * @var integer - */ - protected $expectedCode; - - /** - * @param integer $expected - */ - public function __construct($expected) - { - parent::__construct(); - $this->expectedCode = $expected; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param Exception $other - * @return boolean - */ - protected function matches($other) - { - return (string)$other->getCode() == (string)$this->expectedCode; - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - '%s is equal to expected exception code %s', - $this->exporter->export($other->getCode()), - $this->exporter->export($this->expectedCode) - ); - } - - /** - * @return string - */ - public function toString() - { - return 'exception code is '; - } -} diff --git a/PHPUnit/Framework/Constraint/ExceptionMessage.php b/PHPUnit/Framework/Constraint/ExceptionMessage.php deleted file mode 100644 index 9f82a84de90..00000000000 --- a/PHPUnit/Framework/Constraint/ExceptionMessage.php +++ /dev/null @@ -1,110 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.6 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.6 - */ -class PHPUnit_Framework_Constraint_ExceptionMessage extends PHPUnit_Framework_Constraint -{ - /** - * @var integer - */ - protected $expectedMessage; - - /** - * @param string $expected - */ - public function __construct($expected) - { - parent::__construct(); - $this->expectedMessage = $expected; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param Exception $other - * @return boolean - */ - protected function matches($other) - { - return strpos($other->getMessage(), $this->expectedMessage) !== FALSE; - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - "exception message '%s' contains '%s'", - $other->getMessage(), - $this->expectedMessage - ); - } - - /** - * @return string - */ - public function toString() - { - return 'exception message contains '; - } -} diff --git a/PHPUnit/Framework/Constraint/FileExists.php b/PHPUnit/Framework/Constraint/FileExists.php deleted file mode 100644 index fc57f5c3c1e..00000000000 --- a/PHPUnit/Framework/Constraint/FileExists.php +++ /dev/null @@ -1,102 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that checks if the file(name) that it is evaluated for exists. - * - * The file path to check is passed as $other in evaluate(). - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_FileExists extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return file_exists($other); - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - 'file "%s" exists', - - $other - ); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'file exists'; - } -} diff --git a/PHPUnit/Framework/Constraint/GreaterThan.php b/PHPUnit/Framework/Constraint/GreaterThan.php deleted file mode 100644 index 5b33b44f0dd..00000000000 --- a/PHPUnit/Framework/Constraint/GreaterThan.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the value it is evaluated for is greater - * than a given value. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_GreaterThan extends PHPUnit_Framework_Constraint -{ - /** - * @var numeric - */ - protected $value; - - /** - * @param numeric $value - */ - public function __construct($value) - { - parent::__construct(); - $this->value = $value; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $this->value < $other; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is greater than ' . $this->exporter->export($this->value); - } -} diff --git a/PHPUnit/Framework/Constraint/IsAnything.php b/PHPUnit/Framework/Constraint/IsAnything.php deleted file mode 100644 index 47ae576dc92..00000000000 --- a/PHPUnit/Framework/Constraint/IsAnything.php +++ /dev/null @@ -1,102 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that accepts any input value. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_IsAnything extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - return $returnResult ? TRUE : NULL; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is anything'; - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.5.0 - */ - public function count() - { - return 0; - } -} diff --git a/PHPUnit/Framework/Constraint/IsEmpty.php b/PHPUnit/Framework/Constraint/IsEmpty.php deleted file mode 100644 index c03cc2457e0..00000000000 --- a/PHPUnit/Framework/Constraint/IsEmpty.php +++ /dev/null @@ -1,104 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -/** - * Constraint that checks whether a variable is empty(). - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.0 - */ -class PHPUnit_Framework_Constraint_IsEmpty extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return empty($other); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is empty'; - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - $type = gettype($other); - - return sprintf( - '%s %s %s', - - $type[0] == 'a' || $type[0] == 'o' ? 'an' : 'a', - $type, - $this->toString() - ); - } -} diff --git a/PHPUnit/Framework/Constraint/IsEqual.php b/PHPUnit/Framework/Constraint/IsEqual.php deleted file mode 100644 index 578e23575aa..00000000000 --- a/PHPUnit/Framework/Constraint/IsEqual.php +++ /dev/null @@ -1,217 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Kore Nordmann - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that checks if one value is equal to another. - * - * Equality is checked with PHP's == operator, the operator is explained in - * detail at {@url http://www.php.net/manual/en/types.comparisons.php}. - * Two values are equal if they have the same value disregarding type. - * - * The expected value is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Kore Nordmann - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_IsEqual extends PHPUnit_Framework_Constraint -{ - /** - * @var mixed - */ - protected $value; - - /** - * @var float - */ - protected $delta = 0; - - /** - * @var integer - */ - protected $maxDepth = 10; - - /** - * @var boolean - */ - protected $canonicalize = FALSE; - - /** - * @var boolean - */ - protected $ignoreCase = FALSE; - - /** - * @var PHPUnit_Framework_ComparisonFailure - */ - protected $lastFailure; - - /** - * @param mixed $value - * @param float $delta - * @param integer $maxDepth - * @param boolean $canonicalize - * @param boolean $ignoreCase - */ - public function __construct($value, $delta = 0, $maxDepth = 10, $canonicalize = FALSE, $ignoreCase = FALSE) - { - parent::__construct(); - - if (!is_numeric($delta)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'numeric'); - } - - if (!is_int($maxDepth)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'integer'); - } - - if (!is_bool($canonicalize)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean'); - } - - if (!is_bool($ignoreCase)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(5, 'boolean'); - } - - $this->value = $value; - $this->delta = $delta; - $this->maxDepth = $maxDepth; - $this->canonicalize = $canonicalize; - $this->ignoreCase = $ignoreCase; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $comparatorFactory = PHPUnit_Framework_ComparatorFactory::getDefaultInstance(); - - try { - $comparator = $comparatorFactory->getComparatorFor( - $other, $this->value - ); - - $comparator->assertEquals( - $this->value, - $other, - $this->delta, - $this->canonicalize, - $this->ignoreCase - ); - } - - catch (PHPUnit_Framework_ComparisonFailure $f) { - if ($returnResult) { - return FALSE; - } - - throw new PHPUnit_Framework_ExpectationFailedException( - trim($description . "\n" . $f->getMessage()), - $f - ); - } - - return TRUE; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - $delta = ''; - - if (is_string($this->value)) { - if (strpos($this->value, "\n") !== FALSE) { - return 'is equal to '; - } else { - return sprintf( - 'is equal to ', - - $this->value - ); - } - } else { - if ($this->delta != 0) { - $delta = sprintf( - ' with delta <%F>', - - $this->delta - ); - } - - return sprintf( - 'is equal to %s%s', - - $this->exporter->export($this->value), - $delta - ); - } - } -} diff --git a/PHPUnit/Framework/Constraint/IsFalse.php b/PHPUnit/Framework/Constraint/IsFalse.php deleted file mode 100644 index 2a2b593435d..00000000000 --- a/PHPUnit/Framework/Constraint/IsFalse.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Constraint that accepts FALSE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Constraint_IsFalse extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $other === FALSE; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is false'; - } -} diff --git a/PHPUnit/Framework/Constraint/IsIdentical.php b/PHPUnit/Framework/Constraint/IsIdentical.php deleted file mode 100644 index 6e93073f65a..00000000000 --- a/PHPUnit/Framework/Constraint/IsIdentical.php +++ /dev/null @@ -1,174 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that one value is identical to another. - * - * Identical check is performed with PHP's === operator, the operator is - * explained in detail at - * {@url http://www.php.net/manual/en/types.comparisons.php}. - * Two values are identical if they have the same value and are of the same - * type. - * - * The expected value is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_IsIdentical extends PHPUnit_Framework_Constraint -{ - /** - * @var float - */ - const EPSILON = 0.0000000001; - - /** - * @var mixed - */ - protected $value; - - /** - * @param mixed $value - */ - public function __construct($value) - { - parent::__construct(); - $this->value = $value; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - if (is_double($this->value) && is_double($other) && - !is_infinite($this->value) && !is_infinite($other) && - !is_nan($this->value) && !is_nan($other)) { - $success = abs($this->value - $other) < self::EPSILON; - } - - else { - $success = $this->value === $other; - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $f = NULL; - - // if both values are strings, make sure a diff is generated - if (is_string($this->value) && is_string($other)) { - $f = new PHPUnit_Framework_ComparisonFailure( - $this->value, - $other, - $this->value, - $other - ); - } - - $this->fail($other, $description, $f); - } - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - if (is_object($this->value) && is_object($other)) { - return 'two variables reference the same object'; - } - - if (is_string($this->value) && is_string($other)) { - return 'two strings are identical'; - } - - return parent::failureDescription($other); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - if (is_object($this->value)) { - return 'is identical to an object of class "' . - get_class($this->value) . '"'; - } else { - return 'is identical to ' . - $this->exporter->export($this->value); - } - } -} diff --git a/PHPUnit/Framework/Constraint/IsInstanceOf.php b/PHPUnit/Framework/Constraint/IsInstanceOf.php deleted file mode 100644 index 2936b566d69..00000000000 --- a/PHPUnit/Framework/Constraint/IsInstanceOf.php +++ /dev/null @@ -1,133 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the object it is evaluated for is an instance - * of a given class. - * - * The expected class name is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_IsInstanceOf extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $className; - - /** - * @param string $className - */ - public function __construct($className) - { - parent::__construct(); - $this->className = $className; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return ($other instanceof $this->className); - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - '%s is an instance of %s "%s"', - $this->exporter->shortenedExport($other), - $this->getType(), - $this->className - ); - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return sprintf( - 'is instance of %s "%s"', - $this->getType(), - $this->className - ); - } - - private function getType() { - try { - $reflection = new ReflectionClass($this->className); - if ($reflection->isInterface()) { - return 'interface'; - } - } catch (ReflectionException $e) { - } - return 'class'; - } -} diff --git a/PHPUnit/Framework/Constraint/IsNull.php b/PHPUnit/Framework/Constraint/IsNull.php deleted file mode 100644 index 07f99d363f7..00000000000 --- a/PHPUnit/Framework/Constraint/IsNull.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Constraint that accepts NULL. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Constraint_IsNull extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $other === NULL; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is null'; - } -} diff --git a/PHPUnit/Framework/Constraint/IsTrue.php b/PHPUnit/Framework/Constraint/IsTrue.php deleted file mode 100644 index aa9ae60cfcc..00000000000 --- a/PHPUnit/Framework/Constraint/IsTrue.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Constraint that accepts TRUE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Constraint_IsTrue extends PHPUnit_Framework_Constraint -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $other === TRUE; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is true'; - } -} diff --git a/PHPUnit/Framework/Constraint/IsType.php b/PHPUnit/Framework/Constraint/IsType.php deleted file mode 100644 index 6dfe15ed3cb..00000000000 --- a/PHPUnit/Framework/Constraint/IsType.php +++ /dev/null @@ -1,192 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the value it is evaluated for is of a - * specified type. - * - * The expected value is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_IsType extends PHPUnit_Framework_Constraint -{ - const TYPE_ARRAY = 'array'; - const TYPE_BOOL = 'bool'; - const TYPE_FLOAT = 'float'; - const TYPE_INT = 'int'; - const TYPE_NULL = 'null'; - const TYPE_NUMERIC = 'numeric'; - const TYPE_OBJECT = 'object'; - const TYPE_RESOURCE = 'resource'; - const TYPE_STRING = 'string'; - const TYPE_SCALAR = 'scalar'; - const TYPE_CALLABLE = 'callable'; - - /** - * @var array - */ - protected $types = array( - 'array' => TRUE, - 'boolean' => TRUE, - 'bool' => TRUE, - 'float' => TRUE, - 'integer' => TRUE, - 'int' => TRUE, - 'null' => TRUE, - 'numeric' => TRUE, - 'object' => TRUE, - 'resource' => TRUE, - 'string' => TRUE, - 'scalar' => TRUE, - 'callable' => TRUE - ); - - /** - * @var string - */ - protected $type; - - /** - * @param string $type - * @throws PHPUnit_Framework_Exception - */ - public function __construct($type) - { - parent::__construct(); - - if (!isset($this->types[$type])) { - throw new PHPUnit_Framework_Exception( - sprintf( - 'Type specified for PHPUnit_Framework_Constraint_IsType <%s> ' . - 'is not a valid type.', - $type - ) - ); - } - - $this->type = $type; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - switch ($this->type) { - case 'numeric': { - return is_numeric($other); - } - - case 'integer': - case 'int': { - return is_integer($other); - } - - case 'float': { - return is_float($other); - } - - case 'string': { - return is_string($other); - } - - case 'boolean': - case 'bool': { - return is_bool($other); - } - - case 'null': { - return is_null($other); - } - - case 'array': { - return is_array($other); - } - - case 'object': { - return is_object($other); - } - - case 'resource': { - return is_resource($other); - } - - case 'scalar': { - return is_scalar($other); - } - - case 'callable': { - return is_callable($other); - } - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return sprintf( - 'is of type "%s"', - - $this->type - ); - } -} diff --git a/PHPUnit/Framework/Constraint/JsonMatches.php b/PHPUnit/Framework/Constraint/JsonMatches.php deleted file mode 100644 index 84084d6a3bd..00000000000 --- a/PHPUnit/Framework/Constraint/JsonMatches.php +++ /dev/null @@ -1,127 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bastian Feder - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ - -/** - * Asserts whether or not two JSON objects are equal. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bastian Feder - * @copyright 2011 Bastian Feder - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since Class available since Release 3.7.0 - */ -class PHPUnit_Framework_Constraint_JsonMatches extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $value; - - /** - * Creates a new constraint. - * - * @param string $value - */ - public function __construct($value) - { - parent::__construct(); - $this->value = $value; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * This method can be overridden to implement the evaluation algorithm. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - $decodedOther = json_decode($other); - if (json_last_error()) { - $this->failure_reason = $this->getJsonError(); - return FALSE; - } - - $decodedValue = json_decode($this->value); - if (json_last_error()) { - $this->failure_reason = $this->getJsonError(); - return FALSE; - } - - return $decodedOther == $decodedValue; - } - - /** - * Finds the last occurd JSON error. - * - * @param string $messagePrefix - * @return string The last JSON error prefixed with $messagePrefix. - */ - protected function getJsonError($messagePrefix = 'Json error!') - { - return PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - json_last_error(), - $messagePrefix - ); - } - - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString() - { - return sprintf( - 'matches JSON string "%s"', - $this->value - ); - } -} diff --git a/PHPUnit/Framework/Constraint/JsonMatches/ErrorMessageProvider.php b/PHPUnit/Framework/Constraint/JsonMatches/ErrorMessageProvider.php deleted file mode 100644 index 296155a1717..00000000000 --- a/PHPUnit/Framework/Constraint/JsonMatches/ErrorMessageProvider.php +++ /dev/null @@ -1,106 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bastian Feder - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ - -/** - * Provides human readable messages for each JSON error. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Bastian Feder - * @copyright 2011 Bastian Feder - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since Class available since Release 3.7.0 - */ -class PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider -{ - /** - * Translatets accourd JSON error to a human readable string. - * - * @param string $error - * @return string - */ - public static function determineJsonError($error, $prefix = '') - { - switch (strtoupper($error)) { - case 'JSON_ERROR_NONE': - return; - case 'JSON_ERROR_DEPTH': - return $prefix . 'Maximum stack depth exceeded'; - case 'JSON_ERROR_STATE_MISMATCH': - return $prefix . 'Underflow or the modes mismatch'; - case 'JSON_ERROR_CTRL_CHAR': - return $prefix . 'Unexpected control character found'; - case 'JSON_ERROR_SYNTAX': - return $prefix . 'Syntax error, malformed JSON'; - case 'JSON_ERROR_UTF8': - return $prefix . 'Malformed UTF-8 characters, possibly incorrectly encoded'; - default: - return $prefix . 'Unknown error'; - } - } - - /** - * Translates a given type to a human readable message prefix. - * - * @param string $type - * @return string - */ - public static function translateTypeToPrefix($type) - { - switch (strtolower($type)) { - case 'expected': - $prefix = 'Expected value JSON decode error - '; - break; - case 'actual': - $prefix = 'Actual value JSON decode error - '; - break; - default: - $prefix = ''; - break; - } - return $prefix; - } -} diff --git a/PHPUnit/Framework/Constraint/LessThan.php b/PHPUnit/Framework/Constraint/LessThan.php deleted file mode 100644 index 23f608cd2af..00000000000 --- a/PHPUnit/Framework/Constraint/LessThan.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the value it is evaluated for is less than - * a given value. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_LessThan extends PHPUnit_Framework_Constraint -{ - /** - * @var numeric - */ - protected $value; - - /** - * @param numeric $value - */ - public function __construct($value) - { - parent::__construct(); - $this->value = $value; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return $this->value > $other; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'is less than ' . $this->exporter->export($this->value); - } -} diff --git a/PHPUnit/Framework/Constraint/Not.php b/PHPUnit/Framework/Constraint/Not.php deleted file mode 100644 index acc4d2d7c47..00000000000 --- a/PHPUnit/Framework/Constraint/Not.php +++ /dev/null @@ -1,205 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Logical NOT. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ - -class PHPUnit_Framework_Constraint_Not extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint - */ - protected $constraint; - - /** - * @param PHPUnit_Framework_Constraint $constraint - */ - public function __construct($constraint) - { - parent::__construct(); - - if (!($constraint instanceof PHPUnit_Framework_Constraint)) { - $constraint = new PHPUnit_Framework_Constraint_IsEqual($constraint); - } - - $this->constraint = $constraint; - } - - /** - * @param string $string - * @return string - */ - public static function negate($string) - { - return str_replace( - array( - 'contains ', - 'exists', - 'has ', - 'is ', - 'are ', - 'matches ', - 'starts with ', - 'ends with ', - 'reference ', - 'not not ' - ), - array( - 'does not contain ', - 'does not exist', - 'does not have ', - 'is not ', - 'are not ', - 'does not match ', - 'starts not with ', - 'ends not with ', - 'don\'t reference ', - 'not ' - ), - $string - ); - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = !$this->constraint->evaluate($other, $description, TRUE); - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - switch (get_class($this->constraint)) { - case 'PHPUnit_Framework_Constraint_And': - case 'PHPUnit_Framework_Constraint_Not': - case 'PHPUnit_Framework_Constraint_Or': { - return 'not( ' . $this->constraint->failureDescription($other) . ' )'; - } - break; - - default: { - return self::negate( - $this->constraint->failureDescription($other) - ); - } - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - switch (get_class($this->constraint)) { - case 'PHPUnit_Framework_Constraint_And': - case 'PHPUnit_Framework_Constraint_Not': - case 'PHPUnit_Framework_Constraint_Or': { - return 'not( ' . $this->constraint->toString() . ' )'; - } - break; - - default: { - return self::negate( - $this->constraint->toString() - ); - } - } - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.4.0 - */ - public function count() - { - return count($this->constraint); - } -} diff --git a/PHPUnit/Framework/Constraint/ObjectHasAttribute.php b/PHPUnit/Framework/Constraint/ObjectHasAttribute.php deleted file mode 100644 index 48dd1fce817..00000000000 --- a/PHPUnit/Framework/Constraint/ObjectHasAttribute.php +++ /dev/null @@ -1,77 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the object it is evaluated for has a given - * attribute. - * - * The attribute name is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_ObjectHasAttribute extends PHPUnit_Framework_Constraint_ClassHasAttribute -{ - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - $object = new ReflectionObject($other); - - return $object->hasProperty($this->attributeName); - } -} diff --git a/PHPUnit/Framework/Constraint/Or.php b/PHPUnit/Framework/Constraint/Or.php deleted file mode 100644 index 04291cfa4c0..00000000000 --- a/PHPUnit/Framework/Constraint/Or.php +++ /dev/null @@ -1,157 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Logical OR. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_Or extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint[] - */ - protected $constraints = array(); - - /** - * @param PHPUnit_Framework_Constraint[] $constraints - */ - public function setConstraints(array $constraints) - { - $this->constraints = array(); - - foreach ($constraints as $constraint) { - if (!($constraint instanceof PHPUnit_Framework_Constraint)) { - $constraint = new PHPUnit_Framework_Constraint_IsEqual( - $constraint - ); - } - - $this->constraints[] = $constraint; - } - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = FALSE; - $constraint = NULL; - - foreach ($this->constraints as $constraint) { - if ($constraint->evaluate($other, $description, TRUE)) { - $success = TRUE; - break; - } - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - $text = ''; - - foreach ($this->constraints as $key => $constraint) { - if ($key > 0) { - $text .= ' or '; - } - - $text .= $constraint->toString(); - } - - return $text; - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.4.0 - */ - public function count() - { - $count = 0; - - foreach ($this->constraints as $constraint) { - $count += count($constraint); - } - - return $count; - } -} diff --git a/PHPUnit/Framework/Constraint/PCREMatch.php b/PHPUnit/Framework/Constraint/PCREMatch.php deleted file mode 100644 index a25eae754c7..00000000000 --- a/PHPUnit/Framework/Constraint/PCREMatch.php +++ /dev/null @@ -1,106 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the string it is evaluated for matches - * a regular expression. - * - * Checks a given value using the Perl Compatible Regular Expression extension - * in PHP. The pattern is matched by executing preg_match(). - * - * The pattern string passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_PCREMatch extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $pattern; - - /** - * @param string $pattern - */ - public function __construct($pattern) - { - parent::__construct(); - $this->pattern = $pattern; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return preg_match($this->pattern, $other) > 0; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return sprintf( - 'matches PCRE pattern "%s"', - - $this->pattern - ); - } -} diff --git a/PHPUnit/Framework/Constraint/SameSize.php b/PHPUnit/Framework/Constraint/SameSize.php deleted file mode 100644 index 89b0de6fa84..00000000000 --- a/PHPUnit/Framework/Constraint/SameSize.php +++ /dev/null @@ -1,74 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_Constraint_SameSize extends PHPUnit_Framework_Constraint_Count -{ - /** - * @var integer - */ - protected $expectedCount; - - /** - * @param integer $expected - */ - public function __construct($expected) - { - parent::__construct(); - $this->expectedCount = $this->getCountOf($expected); - } -} diff --git a/PHPUnit/Framework/Constraint/StringContains.php b/PHPUnit/Framework/Constraint/StringContains.php deleted file mode 100644 index 37fb657bee1..00000000000 --- a/PHPUnit/Framework/Constraint/StringContains.php +++ /dev/null @@ -1,124 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the string it is evaluated for contains - * a given string. - * - * Uses strpos() to find the position of the string in the input, if not found - * the evaluaton fails. - * - * The sub-string is passed in the constructor. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_StringContains extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $string; - - /** - * @var boolean - */ - protected $ignoreCase; - - /** - * @param string $string - * @param boolean $ignoreCase - */ - public function __construct($string, $ignoreCase = FALSE) - { - parent::__construct(); - - $this->string = $string; - $this->ignoreCase = $ignoreCase; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - if ($this->ignoreCase) { - return stripos($other, $this->string) !== FALSE; - } else { - return strpos($other, $this->string) !== FALSE; - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - if ($this->ignoreCase) { - $string = strtolower($this->string); - } else { - $string = $this->string; - } - - return sprintf( - 'contains "%s"', - - $string - ); - } -} diff --git a/PHPUnit/Framework/Constraint/StringEndsWith.php b/PHPUnit/Framework/Constraint/StringEndsWith.php deleted file mode 100644 index 30160642813..00000000000 --- a/PHPUnit/Framework/Constraint/StringEndsWith.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Constraint that asserts that the string it is evaluated for ends with a given - * suffix. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Framework_Constraint_StringEndsWith extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $suffix; - - /** - * @param string $suffix - */ - public function __construct($suffix) - { - parent::__construct(); - $this->suffix = $suffix; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return substr($other, 0 - strlen($this->suffix)) == $this->suffix; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'ends with "' . $this->suffix . '"'; - } -} diff --git a/PHPUnit/Framework/Constraint/StringMatches.php b/PHPUnit/Framework/Constraint/StringMatches.php deleted file mode 100644 index 3d26f1050af..00000000000 --- a/PHPUnit/Framework/Constraint/StringMatches.php +++ /dev/null @@ -1,145 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -use SebastianBergmann\Diff; - -/** - * ... - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.0 - */ -class PHPUnit_Framework_Constraint_StringMatches extends PHPUnit_Framework_Constraint_PCREMatch -{ - /** - * @var string - */ - protected $string; - - /** - * @param string $string - */ - public function __construct($string) - { - parent::__construct($string); - - $this->pattern = $this->createPatternFromFormat( - preg_replace('/\r\n/', "\n", $string) - ); - - $this->string = $string; - } - - protected function failureDescription($other) - { - return "format description matches text"; - } - - protected function additionalFailureDescription($other) - { - $from = preg_split('(\r\n|\r|\n)', $this->string); - $to = preg_split('(\r\n|\r|\n)', $other); - - foreach ($from as $index => $line) { - if (isset($to[$index]) && $line !== $to[$index]) { - $line = $this->createPatternFromFormat($line); - - if (preg_match($line, $to[$index]) > 0) { - $from[$index] = $to[$index]; - } - } - } - - $this->string = join("\n", $from); - $other = join("\n", $to); - - $diff = new Diff("--- Expected\n+++ Actual\n"); - - return $diff->diff($this->string, $other); - } - - protected function createPatternFromFormat($string) - { - $string = str_replace( - array( - '%e', - '%s', - '%S', - '%a', - '%A', - '%w', - '%i', - '%d', - '%x', - '%f', - '%c' - ), - array( - '\\' . DIRECTORY_SEPARATOR, - '[^\r\n]+', - '[^\r\n]*', - '.+', - '.*', - '\s*', - '[+-]?\d+', - '\d+', - '[0-9a-fA-F]+', - '[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?', - '.' - ), - preg_quote($string, '/') - ); - return '/^' . $string . '$/s'; - } - -} - diff --git a/PHPUnit/Framework/Constraint/StringStartsWith.php b/PHPUnit/Framework/Constraint/StringStartsWith.php deleted file mode 100644 index 670d0f6f5c9..00000000000 --- a/PHPUnit/Framework/Constraint/StringStartsWith.php +++ /dev/null @@ -1,97 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Constraint that asserts that the string it is evaluated for begins with a - * given prefix. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Framework_Constraint_StringStartsWith extends PHPUnit_Framework_Constraint -{ - /** - * @var string - */ - protected $prefix; - - /** - * @param string $prefix - */ - public function __construct($prefix) - { - parent::__construct(); - $this->prefix = $prefix; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - return strpos($other, $this->prefix) === 0; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'starts with "' . $this->prefix . '"'; - } -} diff --git a/PHPUnit/Framework/Constraint/TraversableContains.php b/PHPUnit/Framework/Constraint/TraversableContains.php deleted file mode 100644 index 9ab9b8d04c7..00000000000 --- a/PHPUnit/Framework/Constraint/TraversableContains.php +++ /dev/null @@ -1,168 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Constraint that asserts that the Traversable it is applied to contains - * a given value. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_TraversableContains extends PHPUnit_Framework_Constraint -{ - /** - * @var boolean - */ - protected $checkForObjectIdentity; - - /** - * @var boolean - */ - protected $checkForNonObjectIdentity; - - /** - * @var mixed - */ - protected $value; - - /** - * @param mixed $value - * @param boolean $checkForObjectIdentity - * @param boolean $checkForNonObjectIdentity - * @throws PHPUnit_Framework_Exception - */ - public function __construct($value, $checkForObjectIdentity = TRUE, $checkForNonObjectIdentity = FALSE) - { - parent::__construct(); - - if (!is_bool($checkForObjectIdentity)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean'); - } - - if (!is_bool($checkForNonObjectIdentity)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'boolean'); - } - - $this->checkForObjectIdentity = $checkForObjectIdentity; - $this->checkForNonObjectIdentity = $checkForNonObjectIdentity; - $this->value = $value; - } - - /** - * Evaluates the constraint for parameter $other. Returns TRUE if the - * constraint is met, FALSE otherwise. - * - * @param mixed $other Value or object to evaluate. - * @return bool - */ - protected function matches($other) - { - if ($other instanceof SplObjectStorage) { - return $other->contains($this->value); - } - - if (is_object($this->value)) { - foreach ($other as $element) { - if (($this->checkForObjectIdentity && - $element === $this->value) || - (!$this->checkForObjectIdentity && - $element == $this->value)) { - return TRUE; - } - } - } else { - foreach ($other as $element) { - if (($this->checkForNonObjectIdentity && - $element === $this->value) || - (!$this->checkForNonObjectIdentity && - $element == $this->value)) { - return TRUE; - } - } - } - - return FALSE; - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - if (is_string($this->value) && strpos($this->value, "\n") !== FALSE) { - return 'contains "' . $this->value . '"'; - } else { - return 'contains ' . $this->exporter->export($this->value); - } - } - - /** - * Returns the description of the failure - * - * The beginning of failure messages is "Failed asserting that" in most - * cases. This method should return the second part of that sentence. - * - * @param mixed $other Evaluated value or object. - * @return string - */ - protected function failureDescription($other) - { - return sprintf( - 'an %s %s', - - is_array($other) ? 'array' : 'iterator', - $this->toString() - ); - } -} diff --git a/PHPUnit/Framework/Constraint/TraversableContainsOnly.php b/PHPUnit/Framework/Constraint/TraversableContainsOnly.php deleted file mode 100644 index c0eff5a270f..00000000000 --- a/PHPUnit/Framework/Constraint/TraversableContainsOnly.php +++ /dev/null @@ -1,136 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.4 - */ - -/** - * Constraint that asserts that the Traversable it is applied to contains - * only values of a given type. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.4 - */ -class PHPUnit_Framework_Constraint_TraversableContainsOnly extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint - */ - protected $constraint; - - /** - * @var string - */ - protected $type; - - /** - * @param string $type - * @param boolean $isNativeType - */ - public function __construct($type, $isNativeType = TRUE) - { - parent::__construct(); - - if ($isNativeType) { - $this->constraint = new PHPUnit_Framework_Constraint_IsType($type); - } else { - $this->constraint = new PHPUnit_Framework_Constraint_IsInstanceOf( - $type - ); - } - - $this->type = $type; - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = TRUE; - - foreach ($other as $item) { - if (!$this->constraint->evaluate($item, '', TRUE)) { - $success = FALSE; - break; - } - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - return 'contains only values of type "' . $this->type . '"'; - } -} diff --git a/PHPUnit/Framework/Constraint/Xor.php b/PHPUnit/Framework/Constraint/Xor.php deleted file mode 100644 index 703a26ee88d..00000000000 --- a/PHPUnit/Framework/Constraint/Xor.php +++ /dev/null @@ -1,162 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Logical XOR. - * - * @package PHPUnit - * @subpackage Framework_Constraint - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_Constraint_Xor extends PHPUnit_Framework_Constraint -{ - /** - * @var PHPUnit_Framework_Constraint[] - */ - protected $constraints = array(); - - /** - * @param PHPUnit_Framework_Constraint[] $constraints - */ - public function setConstraints(array $constraints) - { - $this->constraints = array(); - - foreach ($constraints as $constraint) { - if (!($constraint instanceof PHPUnit_Framework_Constraint)) { - $constraint = new PHPUnit_Framework_Constraint_IsEqual( - $constraint - ); - } - - $this->constraints[] = $constraint; - } - } - - /** - * Evaluates the constraint for parameter $other - * - * If $returnResult is set to FALSE (the default), an exception is thrown - * in case of a failure. NULL is returned otherwise. - * - * If $returnResult is TRUE, the result of the evaluation is returned as - * a boolean value instead: TRUE in case of success, FALSE in case of a - * failure. - * - * @param mixed $other Value or object to evaluate. - * @param string $description Additional information about the test - * @param bool $returnResult Whether to return a result or throw an exception - * @return mixed - * @throws PHPUnit_Framework_ExpectationFailedException - */ - public function evaluate($other, $description = '', $returnResult = FALSE) - { - $success = TRUE; - $lastResult = NULL; - $constraint = NULL; - - foreach ($this->constraints as $constraint) { - $result = $constraint->evaluate($other, $description, TRUE); - - if ($result === $lastResult) { - $success = FALSE; - break; - } - - $lastResult = $result; - } - - if ($returnResult) { - return $success; - } - - if (!$success) { - $this->fail($other, $description); - } - } - - /** - * Returns a string representation of the constraint. - * - * @return string - */ - public function toString() - { - $text = ''; - - foreach ($this->constraints as $key => $constraint) { - if ($key > 0) { - $text .= ' xor '; - } - - $text .= $constraint->toString(); - } - - return $text; - } - - /** - * Counts the number of constraint elements. - * - * @return integer - * @since Method available since Release 3.4.0 - */ - public function count() - { - $count = 0; - - foreach ($this->constraints as $constraint) { - $count += count($constraint); - } - - return $count; - } -} diff --git a/PHPUnit/Framework/Error.php b/PHPUnit/Framework/Error.php deleted file mode 100644 index c286f5edbb3..00000000000 --- a/PHPUnit/Framework/Error.php +++ /dev/null @@ -1,75 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.2.0 - */ - -/** - * Wrapper for PHP errors. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.2.0 - */ -class PHPUnit_Framework_Error extends Exception -{ - /** - * Constructor. - * - * @param string $message - * @param integer $code - * @param string $file - * @param integer $line - * @param Exception $previous - */ - public function __construct($message, $code, $file, $line, Exception $previous = NULL) - { - parent::__construct($message, $code, $previous); - - $this->file = $file; - $this->line = $line; - } -} diff --git a/PHPUnit/Framework/Error/Deprecated.php b/PHPUnit/Framework/Error/Deprecated.php deleted file mode 100644 index 9ca841bfeb2..00000000000 --- a/PHPUnit/Framework/Error/Deprecated.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Wrapper for PHP deprecated errors. - * You can disable deprecated-to-exception conversion by setting - * - * - * PHPUnit_Framework_Error_Deprecated::$enabled = FALSE; - * - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Error_Deprecated extends PHPUnit_Framework_Error -{ - public static $enabled = TRUE; -} diff --git a/PHPUnit/Framework/Error/Notice.php b/PHPUnit/Framework/Error/Notice.php deleted file mode 100644 index a6c53e8c51b..00000000000 --- a/PHPUnit/Framework/Error/Notice.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Wrapper for PHP notices. - * You can disable notice-to-exception conversion by setting - * - * - * PHPUnit_Framework_Error_Notice::$enabled = FALSE; - * - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Error_Notice extends PHPUnit_Framework_Error -{ - public static $enabled = TRUE; -} diff --git a/PHPUnit/Framework/Error/Warning.php b/PHPUnit/Framework/Error/Warning.php deleted file mode 100644 index 0e7c09743f4..00000000000 --- a/PHPUnit/Framework/Error/Warning.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * Wrapper for PHP warnings. - * You can disable notice-to-exception conversion by setting - * - * - * PHPUnit_Framework_Error_Warning::$enabled = FALSE; - * - * - * @package PHPUnit - * @subpackage Framework_Error - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Framework_Error_Warning extends PHPUnit_Framework_Error -{ - public static $enabled = TRUE; -} diff --git a/PHPUnit/Framework/Exception.php b/PHPUnit/Framework/Exception.php deleted file mode 100644 index cad14f777b4..00000000000 --- a/PHPUnit/Framework/Exception.php +++ /dev/null @@ -1,59 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Exception for PHPUnit runtime errors. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Framework_Exception extends RuntimeException -{ -} diff --git a/PHPUnit/Framework/ExpectationFailedException.php b/PHPUnit/Framework/ExpectationFailedException.php deleted file mode 100644 index 7d1e50af725..00000000000 --- a/PHPUnit/Framework/ExpectationFailedException.php +++ /dev/null @@ -1,82 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Exception for expectations which failed their check. - * - * The exception contains the error message and optionally a - * PHPUnit_Framework_ComparisonFailure which is used to - * generate diff output of the failed expectations. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_ExpectationFailedException extends PHPUnit_Framework_AssertionFailedError -{ - /** - * @var PHPUnit_Framework_ComparisonFailure - */ - protected $comparisonFailure; - - public function __construct($message, PHPUnit_Framework_ComparisonFailure $comparisonFailure = NULL, Exception $previous = NULL) - { - $this->comparisonFailure = $comparisonFailure; - - parent::__construct($message, 0, $previous); - } - - /** - * @return PHPUnit_Framework_ComparisonFailure - */ - public function getComparisonFailure() - { - return $this->comparisonFailure; - } -} diff --git a/PHPUnit/Framework/IncompleteTest.php b/PHPUnit/Framework/IncompleteTest.php deleted file mode 100644 index 1603e04e10b..00000000000 --- a/PHPUnit/Framework/IncompleteTest.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A marker interface for marking any exception/error as result of an unit - * test as incomplete implementation or currently not implemented. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 2.0.0 - */ -interface PHPUnit_Framework_IncompleteTest -{ -} diff --git a/PHPUnit/Framework/IncompleteTestError.php b/PHPUnit/Framework/IncompleteTestError.php deleted file mode 100644 index 37ef30cc35d..00000000000 --- a/PHPUnit/Framework/IncompleteTestError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of an incomplete test. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_IncompleteTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_IncompleteTest -{ -} diff --git a/PHPUnit/Framework/InvalidCoversTargetError.php b/PHPUnit/Framework/InvalidCoversTargetError.php deleted file mode 100644 index 8c6fef54595..00000000000 --- a/PHPUnit/Framework/InvalidCoversTargetError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of a test that is skipped because of an invalid @covers annotation. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Framework_InvalidCoversTargetError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest -{ -} diff --git a/PHPUnit/Framework/OutputError.php b/PHPUnit/Framework/OutputError.php deleted file mode 100644 index b33014a85e7..00000000000 --- a/PHPUnit/Framework/OutputError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of a test that printed output. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Framework_OutputError extends PHPUnit_Framework_AssertionFailedError -{ -} diff --git a/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist b/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist deleted file mode 100644 index e499438bd36..00000000000 --- a/PHPUnit/Framework/Process/TestCaseMethod.tpl.dist +++ /dev/null @@ -1,60 +0,0 @@ -setCodeCoverage(new PHP_CodeCoverage); - } - - $result->strictMode({strict}); - - $test = new {className}('{methodName}', unserialize('{data}'), '{dataName}'); - $test->setDependencyInput(unserialize('{dependencyInput}')); - $test->setInIsolation(TRUE); - - ob_end_clean(); - ob_start(); - $test->run($result); - $output = ob_get_clean(); - - print serialize( - array( - 'testResult' => $test->getResult(), - 'numAssertions' => $test->getNumAssertions(), - 'result' => $result, - 'output' => $output - ) - ); - - ob_start(); -} - -{constants} -{included_files} -{globals} - -if (isset($GLOBALS['__PHPUNIT_BOOTSTRAP'])) { - require_once $GLOBALS['__PHPUNIT_BOOTSTRAP']; - unset($GLOBALS['__PHPUNIT_BOOTSTRAP']); -} - -__phpunit_run_isolated_test(); -ob_end_clean(); diff --git a/PHPUnit/Framework/SelfDescribing.php b/PHPUnit/Framework/SelfDescribing.php deleted file mode 100644 index 8661b33cd84..00000000000 --- a/PHPUnit/Framework/SelfDescribing.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Interface for classes that can return a description of itself. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 3.0.0 - */ -interface PHPUnit_Framework_SelfDescribing -{ - /** - * Returns a string representation of the object. - * - * @return string - */ - public function toString(); -} diff --git a/PHPUnit/Framework/SkippedTest.php b/PHPUnit/Framework/SkippedTest.php deleted file mode 100644 index dd9b3762a5a..00000000000 --- a/PHPUnit/Framework/SkippedTest.php +++ /dev/null @@ -1,59 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * A marker interface for marking a unit test as being skipped. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 3.0.0 - */ -interface PHPUnit_Framework_SkippedTest -{ -} diff --git a/PHPUnit/Framework/SkippedTestError.php b/PHPUnit/Framework/SkippedTestError.php deleted file mode 100644 index aa3cab3814b..00000000000 --- a/PHPUnit/Framework/SkippedTestError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of a skipped test. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Framework_SkippedTestError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest -{ -} diff --git a/PHPUnit/Framework/SkippedTestSuiteError.php b/PHPUnit/Framework/SkippedTestSuiteError.php deleted file mode 100644 index eec1b3f4af0..00000000000 --- a/PHPUnit/Framework/SkippedTestSuiteError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of a skipped test suite. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.0 - */ -class PHPUnit_Framework_SkippedTestSuiteError extends PHPUnit_Framework_AssertionFailedError implements PHPUnit_Framework_SkippedTest -{ -} diff --git a/PHPUnit/Framework/SyntheticError.php b/PHPUnit/Framework/SyntheticError.php deleted file mode 100644 index f69361e2297..00000000000 --- a/PHPUnit/Framework/SyntheticError.php +++ /dev/null @@ -1,121 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.0 - */ - -/** - * Creates a synthetic failed assertion. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.0 - */ -class PHPUnit_Framework_SyntheticError extends PHPUnit_Framework_AssertionFailedError -{ - /** - * The synthetic file. - * - * @var string - */ - protected $syntheticFile = ''; - - /** - * The synthetic line number. - * - * @var integer - */ - protected $syntheticLine = 0; - - /** - * The synthetic trace. - * - * @var array - */ - protected $syntheticTrace = array(); - - /** - * Constructor. - * - * @param string $message - * @param integer $code - * @param string $file - * @param integer $line - * @param array $trace - */ - public function __construct($message, $code, $file, $line, $trace) - { - parent::__construct($message, $code); - - $this->syntheticFile = $file; - $this->syntheticLine = $line; - $this->syntheticTrace = $trace; - } - - /** - * @return string - */ - public function getSyntheticFile() - { - return $this->syntheticFile; - } - - /** - * @return integer - */ - public function getSyntheticLine() - { - return $this->syntheticLine; - } - - /** - * @return array - */ - public function getSyntheticTrace() - { - return $this->syntheticTrace; - } -} diff --git a/PHPUnit/Framework/Test.php b/PHPUnit/Framework/Test.php deleted file mode 100644 index 2907270720f..00000000000 --- a/PHPUnit/Framework/Test.php +++ /dev/null @@ -1,66 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A Test can be run and collect its results. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 2.0.0 - */ -interface PHPUnit_Framework_Test extends Countable -{ - /** - * Runs a test and collects its result in a TestResult instance. - * - * @param PHPUnit_Framework_TestResult $result - * @return PHPUnit_Framework_TestResult - */ - public function run(PHPUnit_Framework_TestResult $result = NULL); -} diff --git a/PHPUnit/Framework/TestCase.php b/PHPUnit/Framework/TestCase.php deleted file mode 100644 index 12a98b13821..00000000000 --- a/PHPUnit/Framework/TestCase.php +++ /dev/null @@ -1,1946 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A TestCase defines the fixture to run multiple tests. - * - * To define a TestCase - * - * 1) Implement a subclass of PHPUnit_Framework_TestCase. - * 2) Define instance variables that store the state of the fixture. - * 3) Initialize the fixture state by overriding setUp(). - * 4) Clean-up after a test by overriding tearDown(). - * - * Each test runs in its own fixture so there can be no side effects - * among test runs. - * - * Here is an example: - * - * - * value1 = 2; - * $this->value2 = 3; - * } - * } - * ?> - * - * - * For each test implement a method which interacts with the fixture. - * Verify the expected results with assertions specified by calling - * assert with a boolean. - * - * - * assertTrue($this->value1 + $this->value2 == 5); - * } - * ?> - * - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -abstract class PHPUnit_Framework_TestCase extends PHPUnit_Framework_Assert implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing -{ - /** - * Enable or disable the backup and restoration of the $GLOBALS array. - * Overwrite this attribute in a child class of TestCase. - * Setting this attribute in setUp() has no effect! - * - * @var boolean - */ - protected $backupGlobals = NULL; - - /** - * @var array - */ - protected $backupGlobalsBlacklist = array(); - - /** - * Enable or disable the backup and restoration of static attributes. - * Overwrite this attribute in a child class of TestCase. - * Setting this attribute in setUp() has no effect! - * - * @var boolean - */ - protected $backupStaticAttributes = NULL; - - /** - * @var array - */ - protected $backupStaticAttributesBlacklist = array(); - - /** - * Whether or not this test is to be run in a separate PHP process. - * - * @var boolean - */ - protected $runTestInSeparateProcess = NULL; - - /** - * Whether or not this test should preserve the global state when - * running in a separate PHP process. - * - * @var boolean - */ - protected $preserveGlobalState = TRUE; - - /** - * Whether or not this test is running in a separate PHP process. - * - * @var boolean - */ - private $inIsolation = FALSE; - - /** - * @var array - */ - private $data = array(); - - /** - * @var string - */ - private $dataName = ''; - - /** - * @var boolean - */ - private $useErrorHandler = NULL; - - /** - * @var boolean - */ - private $useOutputBuffering = NULL; - - /** - * The name of the expected Exception. - * - * @var mixed - */ - private $expectedException = NULL; - - /** - * The message of the expected Exception. - * - * @var string - */ - private $expectedExceptionMessage = ''; - - /** - * The code of the expected Exception. - * - * @var integer - */ - private $expectedExceptionCode; - - /** - * The required preconditions for a test. - * - * @var array - */ - private $required = array( - 'PHP' => NULL, - 'PHPUnit' => NULL, - 'OS' => NULL, - 'functions' => array(), - 'extensions' => array() - ); - - /** - * The name of the test case. - * - * @var string - */ - private $name = NULL; - - /** - * @var array - */ - private $dependencies = array(); - - /** - * @var array - */ - private $dependencyInput = array(); - - /** - * @var array - */ - private $iniSettings = array(); - - /** - * @var array - */ - private $locale = array(); - - /** - * @var array - */ - private $mockObjects = array(); - - /** - * @var array - */ - private $mockObjectGenerator; - - /** - * @var integer - */ - private $status; - - /** - * @var string - */ - private $statusMessage = ''; - - /** - * @var integer - */ - private $numAssertions = 0; - - /** - * @var PHPUnit_Framework_TestResult - */ - private $result; - - /** - * @var mixed - */ - private $testResult; - - /** - * @var string - */ - private $output = ''; - - /** - * @var string - */ - private $outputExpectedRegex = NULL; - - /** - * @var string - */ - private $outputExpectedString = NULL; - - /** - * @var bool - */ - private $hasPerformedExpectationsOnOutput = FALSE; - - /** - * @var mixed - */ - private $outputCallback = FALSE; - - /** - * @var boolean - */ - private $outputBufferingActive = FALSE; - - /** - * Constructs a test case with the given name. - * - * @param string $name - * @param array $data - * @param string $dataName - */ - public function __construct($name = NULL, array $data = array(), $dataName = '') - { - if ($name !== NULL) { - $this->setName($name); - } - - $this->data = $data; - $this->dataName = $dataName; - $this->mockObjectGenerator = new PHPUnit_Framework_MockObject_Generator; - } - - /** - * Returns a string representation of the test case. - * - * @return string - */ - public function toString() - { - $class = new ReflectionClass($this); - - $buffer = sprintf( - '%s::%s', - - $class->name, - $this->getName(FALSE) - ); - - return $buffer . $this->getDataSetAsString(); - } - - /** - * Counts the number of test cases executed by run(TestResult result). - * - * @return integer - */ - public function count() - { - return 1; - } - - /** - * Returns the annotations for this test. - * - * @return array - * @since Method available since Release 3.4.0 - */ - public function getAnnotations() - { - return PHPUnit_Util_Test::parseTestMethodAnnotations( - get_class($this), $this->name - ); - } - - /** - * Gets the name of a TestCase. - * - * @param boolean $withDataSet - * @return string - */ - public function getName($withDataSet = TRUE) - { - if ($withDataSet) { - return $this->name . $this->getDataSetAsString(FALSE); - } else { - return $this->name; - } - } - - /** - * Returns the size of the test. - * - * @return integer - * @since Method available since Release 3.6.0 - */ - public function getSize() - { - return PHPUnit_Util_Test::getSize( - get_class($this), $this->getName(FALSE) - ); - } - - /** - * @return string - * @since Method available since Release 3.6.0 - */ - public function getActualOutput() - { - if (!$this->outputBufferingActive) { - return $this->output; - } else { - return ob_get_contents(); - } - } - - /** - * @return string - * @since Method available since Release 3.6.0 - */ - public function hasOutput() - { - if (empty($this->output)) { - return FALSE; - } - - if ($this->outputExpectedString !== NULL || - $this->outputExpectedRegex !== NULL || - $this->hasPerformedExpectationsOnOutput) { - return FALSE; - } - - return TRUE; - } - - /** - * @param string $expectedRegex - * @since Method available since Release 3.6.0 - * @throws PHPUnit_Framework_Exception - */ - public function expectOutputRegex($expectedRegex) - { - if ($this->outputExpectedString !== NULL) { - throw new PHPUnit_Framework_Exception; - } - - if (is_string($expectedRegex) || is_null($expectedRegex)) { - $this->outputExpectedRegex = $expectedRegex; - } - } - - /** - * @param string $expectedString - * @since Method available since Release 3.6.0 - */ - public function expectOutputString($expectedString) - { - if ($this->outputExpectedRegex !== NULL) { - throw new PHPUnit_Framework_Exception; - } - - if (is_string($expectedString) || is_null($expectedString)) { - $this->outputExpectedString = $expectedString; - } - } - - /** - * @return bool - * @since Method available since Release 3.6.5 - */ - public function hasPerformedExpectationsOnOutput() - { - return $this->hasPerformedExpectationsOnOutput; - } - - /** - * @return string - * @since Method available since Release 3.2.0 - */ - public function getExpectedException() - { - return $this->expectedException; - } - - /** - * @param mixed $exceptionName - * @param string $exceptionMessage - * @param integer $exceptionCode - * @since Method available since Release 3.2.0 - */ - public function setExpectedException($exceptionName, $exceptionMessage = '', $exceptionCode = NULL) - { - $this->expectedException = $exceptionName; - $this->expectedExceptionMessage = $exceptionMessage; - $this->expectedExceptionCode = $exceptionCode; - } - - /** - * @since Method available since Release 3.4.0 - */ - protected function setExpectedExceptionFromAnnotation() - { - try { - $expectedException = PHPUnit_Util_Test::getExpectedException( - get_class($this), $this->name - ); - - if ($expectedException !== FALSE) { - $this->setExpectedException( - $expectedException['class'], - $expectedException['message'], - $expectedException['code'] - ); - } - } - - catch (ReflectionException $e) { - } - } - - /** - * @param boolean $useErrorHandler - * @since Method available since Release 3.4.0 - */ - public function setUseErrorHandler($useErrorHandler) - { - $this->useErrorHandler = $useErrorHandler; - } - - /** - * @since Method available since Release 3.4.0 - */ - protected function setUseErrorHandlerFromAnnotation() - { - try { - $useErrorHandler = PHPUnit_Util_Test::getErrorHandlerSettings( - get_class($this), $this->name - ); - - if ($useErrorHandler !== NULL) { - $this->setUseErrorHandler($useErrorHandler); - } - } - - catch (ReflectionException $e) { - } - } - - /** - * @param boolean $useOutputBuffering - * @since Method available since Release 3.4.0 - */ - public function setUseOutputBuffering($useOutputBuffering) - { - $this->useOutputBuffering = $useOutputBuffering; - } - - /** - * @since Method available since Release 3.4.0 - */ - protected function setUseOutputBufferingFromAnnotation() - { - try { - $useOutputBuffering = PHPUnit_Util_Test::getOutputBufferingSettings( - get_class($this), $this->name - ); - - if ($useOutputBuffering !== NULL) { - $this->setUseOutputBuffering($useOutputBuffering); - } - } - - catch (ReflectionException $e) { - } - } - - /** - * @since Method available since Release 3.6.0 - */ - protected function setRequirementsFromAnnotation() - { - try { - $requirements = PHPUnit_Util_Test::getRequirements( - get_class($this), $this->name - ); - - if (isset($requirements['PHP'])) { - $this->required['PHP'] = $requirements['PHP']; - } - - if (isset($requirements['PHPUnit'])) { - $this->required['PHPUnit'] = $requirements['PHPUnit']; - } - - if (isset($requirements['OS'])) { - $this->required['OS'] = $requirements['OS']; - } - - if (isset($requirements['extensions'])) { - $this->required['extensions'] = $requirements['extensions']; - } - - if (isset($requirements['functions'])) { - $this->required['functions'] = $requirements['functions']; - } - } - - catch (ReflectionException $e) { - } - } - - /** - * @since Method available since Release 3.6.0 - */ - protected function checkRequirements() - { - $this->setRequirementsFromAnnotation(); - - $missingRequirements = array(); - - if ($this->required['PHP'] && - version_compare(PHP_VERSION, $this->required['PHP'], '<')) { - $missingRequirements[] = sprintf( - 'PHP %s (or later) is required.', - $this->required['PHP'] - ); - } - - $phpunitVersion = PHPUnit_Runner_Version::id(); - if ($this->required['PHPUnit'] && - version_compare($phpunitVersion, $this->required['PHPUnit'], '<')) { - $missingRequirements[] = sprintf( - 'PHPUnit %s (or later) is required.', - $this->required['PHPUnit'] - ); - } - - if ($this->required['OS'] && - !preg_match($this->required['OS'], PHP_OS)) { - $missingRequirements[] = sprintf( - 'Operating system matching %s is required.', - $this->required['OS'] - ); - } - - foreach ($this->required['functions'] as $requiredFunction) { - if (!function_exists($requiredFunction)) { - $missingRequirements[] = sprintf( - 'Function %s is required.', - $requiredFunction - ); - } - } - - foreach ($this->required['extensions'] as $requiredExtension) { - if (!extension_loaded($requiredExtension)) { - $missingRequirements[] = sprintf( - 'Extension %s is required.', - $requiredExtension - ); - } - } - - if ($missingRequirements) { - $this->markTestSkipped( - implode( - PHP_EOL, - $missingRequirements - ) - ); - } - } - - /** - * Returns the status of this test. - * - * @return integer - * @since Method available since Release 3.1.0 - */ - public function getStatus() - { - return $this->status; - } - - /** - * Returns the status message of this test. - * - * @return string - * @since Method available since Release 3.3.0 - */ - public function getStatusMessage() - { - return $this->statusMessage; - } - - /** - * Returns whether or not this test has failed. - * - * @return boolean - * @since Method available since Release 3.0.0 - */ - public function hasFailed() - { - $status = $this->getStatus(); - - return $status == PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE || - $status == PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; - } - - /** - * Runs the test case and collects the results in a TestResult object. - * If no TestResult object is passed a new one will be created. - * - * @param PHPUnit_Framework_TestResult $result - * @return PHPUnit_Framework_TestResult - * @throws PHPUnit_Framework_Exception - */ - public function run(PHPUnit_Framework_TestResult $result = NULL) - { - if ($result === NULL) { - $result = $this->createResult(); - } - - if (!$this instanceof PHPUnit_Framework_Warning) { - $this->setTestResultObject($result); - $this->setUseErrorHandlerFromAnnotation(); - $this->setUseOutputBufferingFromAnnotation(); - } - - if ($this->useErrorHandler !== NULL) { - $oldErrorHandlerSetting = $result->getConvertErrorsToExceptions(); - $result->convertErrorsToExceptions($this->useErrorHandler); - } - - if (!$this instanceof PHPUnit_Framework_Warning && !$this->handleDependencies()) { - return; - } - - if ($this->runTestInSeparateProcess === TRUE && - $this->inIsolation !== TRUE && - !$this instanceof PHPUnit_Extensions_SeleniumTestCase && - !$this instanceof PHPUnit_Extensions_PhptTestCase) { - $class = new ReflectionClass($this); - - $template = new Text_Template( - sprintf( - '%s%sProcess%sTestCaseMethod.tpl', - - __DIR__, - DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR, - DIRECTORY_SEPARATOR - ) - ); - - if ($this->preserveGlobalState) { - $constants = PHPUnit_Util_GlobalState::getConstantsAsString(); - $globals = PHPUnit_Util_GlobalState::getGlobalsAsString(); - $includedFiles = PHPUnit_Util_GlobalState::getIncludedFilesAsString(); - $iniSettings = PHPUnit_Util_GlobalState::getIniSettingsAsString(); - } else { - $constants = ''; - $globals = ''; - $includedFiles = ''; - $iniSettings = ''; - } - - if ($result->getCollectCodeCoverageInformation()) { - $coverage = 'TRUE'; - } else { - $coverage = 'FALSE'; - } - - if ($result->isStrict()) { - $strict = 'TRUE'; - } else { - $strict = 'FALSE'; - } - - if (defined('PHPUNIT_COMPOSER_INSTALL')) { - $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, TRUE); - } else { - $composerAutoload = '\'\''; - } - - $data = var_export(serialize($this->data), TRUE); - $dependencyInput = var_export(serialize($this->dependencyInput), TRUE); - $includePath = var_export(get_include_path(), TRUE); - // must do these fixes because TestCaseMethod.tpl has unserialize('{data}') in it, and we can't break BC - // the lines above used to use addcslashes() rather than var_export(), which breaks null byte escape sequences - $data = "'." . $data . ".'"; - $dependencyInput = "'." . $dependencyInput . ".'"; - $includePath = "'." . $includePath . ".'"; - - $template->setVar( - array( - 'composerAutoload' => $composerAutoload, - 'filename' => $class->getFileName(), - 'className' => $class->getName(), - 'methodName' => $this->name, - 'collectCodeCoverageInformation' => $coverage, - 'data' => $data, - 'dataName' => $this->dataName, - 'dependencyInput' => $dependencyInput, - 'constants' => $constants, - 'globals' => $globals, - 'include_path' => $includePath, - 'included_files' => $includedFiles, - 'iniSettings' => $iniSettings, - 'strict' => $strict - ) - ); - - $this->prepareTemplate($template); - - $php = PHPUnit_Util_PHP::factory(); - $php->runJob($template->render(), $this, $result); - } else { - $result->run($this); - } - - if ($this->useErrorHandler !== NULL) { - $result->convertErrorsToExceptions($oldErrorHandlerSetting); - } - - $this->result = NULL; - - return $result; - } - - /** - * Runs the bare test sequence. - */ - public function runBare() - { - $this->numAssertions = 0; - - // Backup the $GLOBALS array and static attributes. - if ($this->runTestInSeparateProcess !== TRUE && - $this->inIsolation !== TRUE) { - if ($this->backupGlobals === NULL || - $this->backupGlobals === TRUE) { - PHPUnit_Util_GlobalState::backupGlobals( - $this->backupGlobalsBlacklist - ); - } - - if ($this->backupStaticAttributes === TRUE) { - PHPUnit_Util_GlobalState::backupStaticAttributes( - $this->backupStaticAttributesBlacklist - ); - } - } - - // Start output buffering. - ob_start(); - $this->outputBufferingActive = TRUE; - - // Clean up stat cache. - clearstatcache(); - - // Backup the cwd - $currentWorkingDirectory = getcwd(); - - try { - if ($this->inIsolation) { - $this->setUpBeforeClass(); - } - - $this->setExpectedExceptionFromAnnotation(); - $this->setUp(); - $this->checkRequirements(); - $this->assertPreConditions(); - $this->testResult = $this->runTest(); - $this->verifyMockObjects(); - $this->assertPostConditions(); - $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; - } - - catch (PHPUnit_Framework_IncompleteTest $e) { - $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; - $this->statusMessage = $e->getMessage(); - } - - catch (PHPUnit_Framework_SkippedTest $e) { - $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; - $this->statusMessage = $e->getMessage(); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; - $this->statusMessage = $e->getMessage(); - } - - catch (Exception $e) { - $this->status = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; - $this->statusMessage = $e->getMessage(); - } - - // Clean up the mock objects. - $this->mockObjects = array(); - - // Tear down the fixture. An exception raised in tearDown() will be - // caught and passed on when no exception was raised before. - try { - $this->tearDown(); - - if ($this->inIsolation) { - $this->tearDownAfterClass(); - } - } - - catch (Exception $_e) { - if (!isset($e)) { - $e = $_e; - } - } - - // Stop output buffering. - if ($this->outputCallback === FALSE) { - $this->output = ob_get_contents(); - } else { - $this->output = call_user_func_array( - $this->outputCallback, array(ob_get_contents()) - ); - } - - ob_end_clean(); - $this->outputBufferingActive = FALSE; - - // Clean up stat cache. - clearstatcache(); - - // Restore the cwd if it was changed by the test - if ($currentWorkingDirectory != getcwd()) { - chdir($currentWorkingDirectory); - } - - // Restore the $GLOBALS array and static attributes. - if ($this->runTestInSeparateProcess !== TRUE && - $this->inIsolation !== TRUE) { - if ($this->backupGlobals === NULL || - $this->backupGlobals === TRUE) { - PHPUnit_Util_GlobalState::restoreGlobals( - $this->backupGlobalsBlacklist - ); - } - - if ($this->backupStaticAttributes === TRUE) { - PHPUnit_Util_GlobalState::restoreStaticAttributes(); - } - } - - // Clean up INI settings. - foreach ($this->iniSettings as $varName => $oldValue) { - ini_set($varName, $oldValue); - } - - $this->iniSettings = array(); - - // Clean up locale settings. - foreach ($this->locale as $category => $locale) { - setlocale($category, $locale); - } - - // Perform assertion on output. - if (!isset($e)) { - try { - if ($this->outputExpectedRegex !== NULL) { - $this->hasPerformedExpectationsOnOutput = TRUE; - $this->assertRegExp($this->outputExpectedRegex, $this->output); - $this->outputExpectedRegex = NULL; - } - - else if ($this->outputExpectedString !== NULL) { - $this->hasPerformedExpectationsOnOutput = TRUE; - $this->assertEquals($this->outputExpectedString, $this->output); - $this->outputExpectedString = NULL; - } - } - - catch (Exception $_e) { - $e = $_e; - } - } - - // Workaround for missing "finally". - if (isset($e)) { - $this->onNotSuccessfulTest($e); - } - } - - /** - * Override to run the test and assert its state. - * - * @return mixed - * @throws Exception|PHPUnit_Framework_Exception - * @throws PHPUnit_Framework_Exception - */ - protected function runTest() - { - if ($this->name === NULL) { - throw new PHPUnit_Framework_Exception( - 'PHPUnit_Framework_TestCase::$name must not be NULL.' - ); - } - - try { - $class = new ReflectionClass($this); - $method = $class->getMethod($this->name); - } - - catch (ReflectionException $e) { - $this->fail($e->getMessage()); - } - - try { - $testResult = $method->invokeArgs( - $this, array_merge($this->data, $this->dependencyInput) - ); - } - - catch (Exception $e) { - $checkException = FALSE; - - if (is_string($this->expectedException)) { - $checkException = TRUE; - - if ($e instanceof PHPUnit_Framework_Exception) { - $checkException = FALSE; - } - - $reflector = new ReflectionClass($this->expectedException); - - if ($this->expectedException == 'PHPUnit_Framework_Exception' || - $reflector->isSubclassOf('PHPUnit_Framework_Exception')) { - $checkException = TRUE; - } - } - - if ($checkException) { - $this->assertThat( - $e, - new PHPUnit_Framework_Constraint_Exception( - $this->expectedException - ) - ); - - if (is_string($this->expectedExceptionMessage) && - !empty($this->expectedExceptionMessage)) { - $this->assertThat( - $e, - new PHPUnit_Framework_Constraint_ExceptionMessage( - $this->expectedExceptionMessage - ) - ); - } - - if ($this->expectedExceptionCode !== NULL) { - $this->assertThat( - $e, - new PHPUnit_Framework_Constraint_ExceptionCode( - $this->expectedExceptionCode - ) - ); - } - - return; - } else { - throw $e; - } - } - - if ($this->expectedException !== NULL) { - $this->assertThat( - NULL, - new PHPUnit_Framework_Constraint_Exception( - $this->expectedException - ) - ); - } - - return $testResult; - } - - /** - * Verifies the mock object expectations. - * - * @since Method available since Release 3.5.0 - */ - protected function verifyMockObjects() - { - foreach ($this->mockObjects as $mockObject) { - if ($mockObject->__phpunit_hasMatchers()) { - $this->numAssertions++; - } - - $mockObject->__phpunit_verify(); - $mockObject->__phpunit_cleanup(); - } - } - - /** - * Sets the name of a TestCase. - * - * @param string - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * Sets the dependencies of a TestCase. - * - * @param array $dependencies - * @since Method available since Release 3.4.0 - */ - public function setDependencies(array $dependencies) - { - $this->dependencies = $dependencies; - } - - /** - * Sets - * - * @param array $dependencyInput - * @since Method available since Release 3.4.0 - */ - public function setDependencyInput(array $dependencyInput) - { - $this->dependencyInput = $dependencyInput; - } - - /** - * Calling this method in setUp() has no effect! - * - * @param boolean $backupGlobals - * @since Method available since Release 3.3.0 - */ - public function setBackupGlobals($backupGlobals) - { - if (is_null($this->backupGlobals) && is_bool($backupGlobals)) { - $this->backupGlobals = $backupGlobals; - } - } - - /** - * Calling this method in setUp() has no effect! - * - * @param boolean $backupStaticAttributes - * @since Method available since Release 3.4.0 - */ - public function setBackupStaticAttributes($backupStaticAttributes) - { - if (is_null($this->backupStaticAttributes) && - is_bool($backupStaticAttributes)) { - $this->backupStaticAttributes = $backupStaticAttributes; - } - } - - /** - * @param boolean $runTestInSeparateProcess - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.4.0 - */ - public function setRunTestInSeparateProcess($runTestInSeparateProcess) - { - if (is_bool($runTestInSeparateProcess)) { - if ($this->runTestInSeparateProcess === NULL) { - $this->runTestInSeparateProcess = $runTestInSeparateProcess; - } - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * @param boolean $preserveGlobalState - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.4.0 - */ - public function setPreserveGlobalState($preserveGlobalState) - { - if (is_bool($preserveGlobalState)) { - $this->preserveGlobalState = $preserveGlobalState; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * @param boolean $inIsolation - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.4.0 - */ - public function setInIsolation($inIsolation) - { - if (is_bool($inIsolation)) { - $this->inIsolation = $inIsolation; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * @return mixed - * @since Method available since Release 3.4.0 - */ - public function getResult() - { - return $this->testResult; - } - - /** - * @param mixed $result - * @since Method available since Release 3.4.0 - */ - public function setResult($result) - { - $this->testResult = $result; - } - - /** - * @param callable $callback - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.6.0 - */ - public function setOutputCallback($callback) - { - if (!is_callable($callback)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'callback'); - } - - $this->outputCallback = $callback; - } - - /** - * @return PHPUnit_Framework_TestResult - * @since Method available since Release 3.5.7 - */ - public function getTestResultObject() - { - return $this->result; - } - - /** - * @param PHPUnit_Framework_TestResult $result - * @since Method available since Release 3.6.0 - */ - public function setTestResultObject(PHPUnit_Framework_TestResult $result) - { - $this->result = $result; - } - - /** - * This method is a wrapper for the ini_set() function that automatically - * resets the modified php.ini setting to its original value after the - * test is run. - * - * @param string $varName - * @param string $newValue - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.0.0 - */ - protected function iniSet($varName, $newValue) - { - if (!is_string($varName)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - $currentValue = ini_set($varName, $newValue); - - if ($currentValue !== FALSE) { - $this->iniSettings[$varName] = $currentValue; - } else { - throw new PHPUnit_Framework_Exception( - sprintf( - 'INI setting "%s" could not be set to "%s".', - $varName, - $newValue - ) - ); - } - } - - /** - * This method is a wrapper for the setlocale() function that automatically - * resets the locale to its original value after the test is run. - * - * @param integer $category - * @param string $locale - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.1.0 - */ - protected function setLocale() - { - $args = func_get_args(); - - if (count($args) < 2) { - throw new PHPUnit_Framework_Exception; - } - - $category = $args[0]; - $locale = $args[1]; - - $categories = array( - LC_ALL, LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME - ); - - if (defined('LC_MESSAGES')) { - $categories[] = LC_MESSAGES; - } - - if (!in_array($category, $categories)) { - throw new PHPUnit_Framework_Exception; - } - - if (!is_array($locale) && !is_string($locale)) { - throw new PHPUnit_Framework_Exception; - } - - $this->locale[$category] = setlocale($category, NULL); - - $result = call_user_func_array( 'setlocale', $args ); - - if ($result === FALSE) { - throw new PHPUnit_Framework_Exception( - 'The locale functionality is not implemented on your platform, ' . - 'the specified locale does not exist or the category name is ' . - 'invalid.' - ); - } - } - - /** - * Returns a mock object for the specified class. - * - * @param string $originalClassName - * @param array $methods - * @param array $arguments - * @param string $mockClassName - * @param boolean $callOriginalConstructor - * @param boolean $callOriginalClone - * @param boolean $callAutoload - * @param boolean $cloneArguments - * @return PHPUnit_Framework_MockObject_MockObject - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.0.0 - */ - public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = FALSE) - { - $mockObject = $this->mockObjectGenerator->getMock( - $originalClassName, - $methods, - $arguments, - $mockClassName, - $callOriginalConstructor, - $callOriginalClone, - $callAutoload, - $cloneArguments - ); - - $this->mockObjects[] = $mockObject; - - return $mockObject; - } - - /** - * Returns a builder object to create mock objects using a fluent interface. - * - * @param string $className - * @return PHPUnit_Framework_MockObject_MockBuilder - * @since Method available since Release 3.5.0 - */ - public function getMockBuilder($className) - { - return new PHPUnit_Framework_MockObject_MockBuilder( - $this, $className - ); - } - - /** - * Mocks the specified class and returns the name of the mocked class. - * - * @param string $originalClassName - * @param array $methods - * @param array $arguments - * @param string $mockClassName - * @param boolean $callOriginalConstructor - * @param boolean $callOriginalClone - * @param boolean $callAutoload - * @param boolean $cloneArguments - * @return string - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.5.0 - */ - protected function getMockClass($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = FALSE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = FALSE) - { - $mock = $this->getMock( - $originalClassName, - $methods, - $arguments, - $mockClassName, - $callOriginalConstructor, - $callOriginalClone, - $callAutoload, - $cloneArguments - ); - - return get_class($mock); - } - - /** - * Returns a mock object for the specified abstract class with all abstract - * methods of the class mocked. Concrete methods to mock can be specified with - * the last parameter - * - * @param string $originalClassName - * @param array $arguments - * @param string $mockClassName - * @param boolean $callOriginalConstructor - * @param boolean $callOriginalClone - * @param boolean $callAutoload - * @param array $mockedMethods - * @param boolean $cloneArguments - * @return PHPUnit_Framework_MockObject_MockObject - * @since Method available since Release 3.4.0 - * @throws PHPUnit_Framework_Exception - */ - public function getMockForAbstractClass($originalClassName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $mockedMethods = array(), $cloneArguments = FALSE) - { - $mockObject = $this->mockObjectGenerator->getMockForAbstractClass( - $originalClassName, - $arguments, - $mockClassName, - $callOriginalConstructor, - $callOriginalClone, - $callAutoload, - $mockedMethods, - $cloneArguments - ); - - $this->mockObjects[] = $mockObject; - - return $mockObject; - } - - /** - * Returns a mock object based on the given WSDL file. - * - * @param string $wsdlFile - * @param string $originalClassName - * @param string $mockClassName - * @param array $methods - * @param boolean $callOriginalConstructor - * @param array $options An array of options passed to SOAPClient::_construct - * @return PHPUnit_Framework_MockObject_MockObject - * @since Method available since Release 3.4.0 - */ - protected function getMockFromWsdl($wsdlFile, $originalClassName = '', $mockClassName = '', array $methods = array(), $callOriginalConstructor = TRUE, array $options = array()) - { - if ($originalClassName === '') { - $originalClassName = str_replace( - '.wsdl', '', basename($wsdlFile) - ); - } - - if (!class_exists($originalClassName)) { - eval( - $this->mockObjectGenerator->generateClassFromWsdl( - $wsdlFile, $originalClassName, $methods, $options - ) - ); - } - - return $this->getMock( - $originalClassName, - $methods, - array('', $options), - $mockClassName, - $callOriginalConstructor, - FALSE, - FALSE - ); - } - - /** - * Returns a mock object for the specified trait with all abstract methods - * of the trait mocked. Concrete methods to mock can be specified with the - * `$mockedMethods` parameter. - * - * @param string $traitName - * @param array $arguments - * @param string $mockClassName - * @param boolean $callOriginalConstructor - * @param boolean $callOriginalClone - * @param boolean $callAutoload - * @param array $mockedMethods - * @param boolean $cloneArguments - * @return PHPUnit_Framework_MockObject_MockObject - * @since Method available since Release 3.8.1 - * @throws PHPUnit_Framework_Exception - */ - public function getMockForTrait($traitName, array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $mockedMethods = array(), $cloneArguments = FALSE) - { - $mockObject = $this->mockObjectGenerator->getMockForTrait( - $traitName, - $arguments, - $mockClassName, - $callOriginalConstructor, - $callOriginalClone, - $callAutoload, - $mockedMethods, - $cloneArguments - ); - - $this->mockObjects[] = $mockObject; - - return $mockObject; - } - - /** - * Returns an object for the specified trait. - * - * @param string $traitName - * @param array $arguments - * @param string $traitClassName - * @param boolean $callOriginalConstructor - * @param boolean $callOriginalClone - * @param boolean $callAutoload - * @param boolean $cloneArguments - * @return object - * @since Method available since Release 3.6.0 - * @throws PHPUnit_Framework_Exception - */ - protected function getObjectForTrait($traitName, array $arguments = array(), $traitClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = FALSE) - { - return $this->mockObjectGenerator->getObjectForTrait( - $traitName, - $arguments, - $traitClassName, - $callOriginalConstructor, - $callOriginalClone, - $callAutoload, - $cloneArguments - ); - } - - /** - * Adds a value to the assertion counter. - * - * @param integer $count - * @since Method available since Release 3.3.3 - */ - public function addToAssertionCount($count) - { - $this->numAssertions += $count; - } - - /** - * Returns the number of assertions performed by this test. - * - * @return integer - * @since Method available since Release 3.3.0 - */ - public function getNumAssertions() - { - return $this->numAssertions; - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is executed zero or more times. - * - * @return PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount - * @since Method available since Release 3.0.0 - */ - public static function any() - { - return new PHPUnit_Framework_MockObject_Matcher_AnyInvokedCount; - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is never executed. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ - public static function never() - { - return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(0); - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is executed at least once. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce - * @since Method available since Release 3.0.0 - */ - public static function atLeastOnce() - { - return new PHPUnit_Framework_MockObject_Matcher_InvokedAtLeastOnce; - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is executed exactly once. - * - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ - public static function once() - { - return new PHPUnit_Framework_MockObject_Matcher_InvokedCount(1); - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is executed exactly $count times. - * - * @param integer $count - * @return PHPUnit_Framework_MockObject_Matcher_InvokedCount - * @since Method available since Release 3.0.0 - */ - public static function exactly($count) - { - return new PHPUnit_Framework_MockObject_Matcher_InvokedCount($count); - } - - /** - * Returns a matcher that matches when the method it is evaluated for - * is invoked at the given $index. - * - * @param integer $index - * @return PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex - * @since Method available since Release 3.0.0 - */ - public static function at($index) - { - return new PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex($index); - } - - /** - * - * - * @param mixed $value - * @return PHPUnit_Framework_MockObject_Stub_Return - * @since Method available since Release 3.0.0 - */ - public static function returnValue($value) - { - return new PHPUnit_Framework_MockObject_Stub_Return($value); - } - - /** - * - * - * @param array $valueMap - * @return PHPUnit_Framework_MockObject_Stub_ReturnValueMap - * @since Method available since Release 3.6.0 - */ - public static function returnValueMap(array $valueMap) - { - return new PHPUnit_Framework_MockObject_Stub_ReturnValueMap($valueMap); - } - - /** - * - * - * @param integer $argumentIndex - * @return PHPUnit_Framework_MockObject_Stub_ReturnArgument - * @since Method available since Release 3.3.0 - */ - public static function returnArgument($argumentIndex) - { - return new PHPUnit_Framework_MockObject_Stub_ReturnArgument( - $argumentIndex - ); - } - - /** - * - * - * @param mixed $callback - * @return PHPUnit_Framework_MockObject_Stub_ReturnCallback - * @since Method available since Release 3.3.0 - */ - public static function returnCallback($callback) - { - return new PHPUnit_Framework_MockObject_Stub_ReturnCallback($callback); - } - - /** - * Returns the current object. - * - * This method is useful when mocking a fluent interface. - * - * @return PHPUnit_Framework_MockObject_Stub_ReturnSelf - * @since Method available since Release 3.6.0 - */ - public static function returnSelf() - { - return new PHPUnit_Framework_MockObject_Stub_ReturnSelf(); - } - - /** - * - * - * @param Exception $exception - * @return PHPUnit_Framework_MockObject_Stub_Exception - * @since Method available since Release 3.1.0 - */ - public static function throwException(Exception $exception) - { - return new PHPUnit_Framework_MockObject_Stub_Exception($exception); - } - - /** - * @param mixed $value, ... - * @return PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls - * @since Method available since Release 3.0.0 - */ - public static function onConsecutiveCalls() - { - $args = func_get_args(); - - return new PHPUnit_Framework_MockObject_Stub_ConsecutiveCalls($args); - } - - /** - * @param mixed $data - * @return string - * @since Method available since Release 3.2.1 - */ - protected function dataToString($data) - { - $result = array(); - - // There seems to be no other way to check arrays for recursion - // http://www.php.net/manual/en/language.types.array.php#73936 - preg_match_all('/\n \[(\w+)\] => Array\s+\*RECURSION\*/', print_r($data, TRUE), $matches); - $recursiveKeys = array_unique($matches[1]); - - // Convert to valid array keys - // Numeric integer strings are automatically converted to integers - // by PHP - foreach ($recursiveKeys as $key => $recursiveKey) { - if ((string)(integer)$recursiveKey === $recursiveKey) { - $recursiveKeys[$key] = (integer)$recursiveKey; - } - } - - foreach ($data as $key => $_data) { - if (in_array($key, $recursiveKeys, TRUE)) { - $result[] = '*RECURSION*'; - } - - else if (is_array($_data)) { - $result[] = 'array(' . $this->dataToString($_data) . ')'; - } - - else if (is_object($_data)) { - $object = new ReflectionObject($_data); - - if ($object->hasMethod('__toString')) { - $result[] = (string)$_data; - } else { - $result[] = get_class($_data); - } - } - - else if (is_resource($_data)) { - $result[] = ''; - } - - else { - $result[] = var_export($_data, TRUE); - } - } - - return join(', ', $result); - } - - /** - * Gets the data set description of a TestCase. - * - * @param boolean $includeData - * @return string - * @since Method available since Release 3.3.0 - */ - protected function getDataSetAsString($includeData = TRUE) - { - $buffer = ''; - - if (!empty($this->data)) { - if (is_int($this->dataName)) { - $buffer .= sprintf(' with data set #%d', $this->dataName); - } else { - $buffer .= sprintf(' with data set "%s"', $this->dataName); - } - - if ($includeData) { - $buffer .= sprintf(' (%s)', $this->dataToString($this->data)); - } - } - - return $buffer; - } - - /** - * Creates a default TestResult object. - * - * @return PHPUnit_Framework_TestResult - */ - protected function createResult() - { - return new PHPUnit_Framework_TestResult; - } - - /** - * @since Method available since Release 3.5.4 - */ - protected function handleDependencies() - { - if (!empty($this->dependencies) && !$this->inIsolation) { - $className = get_class($this); - $passed = $this->result->passed(); - $passedKeys = array_keys($passed); - $numKeys = count($passedKeys); - - for ($i = 0; $i < $numKeys; $i++) { - $pos = strpos($passedKeys[$i], ' with data set'); - - if ($pos !== FALSE) { - $passedKeys[$i] = substr($passedKeys[$i], 0, $pos); - } - } - - $passedKeys = array_flip(array_unique($passedKeys)); - - foreach ($this->dependencies as $dependency) { - if (strpos($dependency, '::') === FALSE) { - $dependency = $className . '::' . $dependency; - } - - if (!isset($passedKeys[$dependency])) { - $this->result->addError( - $this, - new PHPUnit_Framework_SkippedTestError( - sprintf( - 'This test depends on "%s" to pass.', $dependency - ) - ), - 0 - ); - - return FALSE; - } - - if (isset($passed[$dependency])) { - if ($passed[$dependency]['size'] > $this->getSize()) { - $this->result->addError( - $this, - new PHPUnit_Framework_SkippedTestError( - 'This test depends on a test that is larger than itself.' - ), - 0 - ); - - return FALSE; - } - - $this->dependencyInput[] = $passed[$dependency]['result']; - } else { - $this->dependencyInput[] = NULL; - } - } - } - - return TRUE; - } - - /** - * This method is called before the first test of this test class is run. - * - * @since Method available since Release 3.4.0 - */ - public static function setUpBeforeClass() - { - } - - /** - * Sets up the fixture, for example, open a network connection. - * This method is called before a test is executed. - * - */ - protected function setUp() - { - } - - /** - * Performs assertions shared by all tests of a test case. - * - * This method is called before the execution of a test starts - * and after setUp() is called. - * - * @since Method available since Release 3.2.8 - */ - protected function assertPreConditions() - { - } - - /** - * Performs assertions shared by all tests of a test case. - * - * This method is called before the execution of a test ends - * and before tearDown() is called. - * - * @since Method available since Release 3.2.8 - */ - protected function assertPostConditions() - { - } - - /** - * Tears down the fixture, for example, close a network connection. - * This method is called after a test is executed. - */ - protected function tearDown() - { - } - - /** - * This method is called after the last test of this test class is run. - * - * @since Method available since Release 3.4.0 - */ - public static function tearDownAfterClass() - { - } - - /** - * This method is called when a test method did not execute successfully. - * - * @param Exception $e - * @since Method available since Release 3.4.0 - * @throws Exception - */ - protected function onNotSuccessfulTest(Exception $e) - { - throw $e; - } - - /** - * Performs custom preparations on the process isolation template. - * - * @param Text_Template $template - * @since Method available since Release 3.4.0 - */ - protected function prepareTemplate(Text_Template $template) - { - } -} diff --git a/PHPUnit/Framework/TestFailure.php b/PHPUnit/Framework/TestFailure.php deleted file mode 100644 index 322084912c6..00000000000 --- a/PHPUnit/Framework/TestFailure.php +++ /dev/null @@ -1,179 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A TestFailure collects a failed test together with the caught exception. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_TestFailure -{ - /** - * @var PHPUnit_Framework_Test - */ - protected $failedTest; - - /** - * @var Exception - */ - protected $thrownException; - - /** - * Constructs a TestFailure with the given test and exception. - * - * @param PHPUnit_Framework_Test $failedTest - * @param Exception $thrownException - */ - public function __construct(PHPUnit_Framework_Test $failedTest, Exception $thrownException) - { - $this->failedTest = $failedTest; - $this->thrownException = $thrownException; - } - - /** - * Returns a short description of the failure. - * - * @return string - */ - public function toString() - { - return sprintf( - '%s: %s', - - $this->failedTest, - $this->thrownException->getMessage() - ); - } - - /** - * Returns a description for the thrown exception. - * - * @return string - * @since Method available since Release 3.4.0 - */ - public function getExceptionAsString() - { - return self::exceptionToString($this->thrownException); - } - - /** - * Returns a description for an exception. - * - * @param Exception $e - * @return string - * @since Method available since Release 3.2.0 - */ - public static function exceptionToString(Exception $e) - { - if ($e instanceof PHPUnit_Framework_SelfDescribing) { - $buffer = $e->toString(); - - if ($e instanceof PHPUnit_Framework_ExpectationFailedException && $e->getComparisonFailure()) { - $buffer = $buffer . "\n" . $e->getComparisonFailure()->getDiff(); - } - - if (!empty($buffer)) { - $buffer = trim($buffer) . "\n"; - } - } - - else if ($e instanceof PHPUnit_Framework_Error) { - $buffer = $e->getMessage() . "\n"; - } - - else { - $buffer = get_class($e) . ': ' . $e->getMessage() . "\n"; - } - - return $buffer; - } - - /** - * Gets the failed test. - * - * @return PHPUnit_Framework_Test - */ - public function failedTest() - { - return $this->failedTest; - } - - /** - * Gets the thrown exception. - * - * @return Exception - */ - public function thrownException() - { - return $this->thrownException; - } - - /** - * Returns the exception's message. - * - * @return string - */ - public function exceptionMessage() - { - return $this->thrownException()->getMessage(); - } - - /** - * Returns TRUE if the thrown exception - * is of type AssertionFailedError. - * - * @return boolean - */ - public function isFailure() - { - return ($this->thrownException() instanceof PHPUnit_Framework_AssertionFailedError); - } -} diff --git a/PHPUnit/Framework/TestListener.php b/PHPUnit/Framework/TestListener.php deleted file mode 100644 index e64ef24c47d..00000000000 --- a/PHPUnit/Framework/TestListener.php +++ /dev/null @@ -1,126 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A Listener for test progress. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 2.0.0 - */ -interface PHPUnit_Framework_TestListener -{ - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time); - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time); - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time); - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time); - - /** - * A test suite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite); - - /** - * A test suite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite); - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test); - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time); -} diff --git a/PHPUnit/Framework/TestResult.php b/PHPUnit/Framework/TestResult.php deleted file mode 100644 index 9af35a5483d..00000000000 --- a/PHPUnit/Framework/TestResult.php +++ /dev/null @@ -1,1017 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A TestResult collects the results of executing a test case. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_TestResult implements Countable -{ - /** - * @var boolean - */ - protected static $xdebugLoaded = NULL; - - /** - * @var boolean - */ - protected static $useXdebug = NULL; - - /** - * @var array - */ - protected $passed = array(); - - /** - * @var array - */ - protected $errors = array(); - - /** - * @var array - */ - protected $deprecatedFeatures = array(); - - /** - * @var array - */ - protected $failures = array(); - - /** - * @var array - */ - protected $notImplemented = array(); - - /** - * @var array - */ - protected $skipped = array(); - - /** - * @var array - */ - protected $listeners = array(); - - /** - * @var integer - */ - protected $runTests = 0; - - /** - * @var float - */ - protected $time = 0; - - /** - * @var PHPUnit_Framework_TestSuite - */ - protected $topTestSuite = NULL; - - /** - * Code Coverage information. - * - * @var PHP_CodeCoverage - */ - protected $codeCoverage; - - /** - * @var boolean - */ - protected $convertErrorsToExceptions = TRUE; - - /** - * @var boolean - */ - protected $stop = FALSE; - - /** - * @var boolean - */ - protected $stopOnError = FALSE; - - /** - * @var boolean - */ - protected $stopOnFailure = FALSE; - - /** - * @var boolean - */ - protected $strictMode = FALSE; - - /** - * @var boolean - */ - protected $stopOnIncomplete = FALSE; - - /** - * @var boolean - */ - protected $stopOnSkipped = FALSE; - - /** - * @var boolean - */ - protected $lastTestFailed = FALSE; - - /** - * @var integer - */ - protected $timeoutForSmallTests = 1; - - /** - * @var integer - */ - protected $timeoutForMediumTests = 10; - - /** - * @var integer - */ - protected $timeoutForLargeTests = 60; - - /** - * Registers a TestListener. - * - * @param PHPUnit_Framework_TestListener - */ - public function addListener(PHPUnit_Framework_TestListener $listener) - { - $this->listeners[] = $listener; - } - - /** - * Unregisters a TestListener. - * - * @param PHPUnit_Framework_TestListener $listener - */ - public function removeListener(PHPUnit_Framework_TestListener $listener) - { - foreach ($this->listeners as $key => $_listener) { - if ($listener === $_listener) { - unset($this->listeners[$key]); - } - } - } - - /** - * Flushes all flushable TestListeners. - * - * @since Method available since Release 3.0.0 - */ - public function flushListeners() - { - foreach ($this->listeners as $listener) { - if ($listener instanceof PHPUnit_Util_Printer) { - $listener->flush(); - } - } - } - - /** - * Adds an error to the list of errors. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($e instanceof PHPUnit_Framework_IncompleteTest) { - $this->notImplemented[] = new PHPUnit_Framework_TestFailure( - $test, $e - ); - - $notifyMethod = 'addIncompleteTest'; - - if ($this->stopOnIncomplete) { - $this->stop(); - } - } - - else if ($e instanceof PHPUnit_Framework_SkippedTest) { - $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e); - $notifyMethod = 'addSkippedTest'; - - if ($this->stopOnSkipped) { - $this->stop(); - } - } - - else { - $this->errors[] = new PHPUnit_Framework_TestFailure($test, $e); - $notifyMethod = 'addError'; - - if ($this->stopOnError || $this->stopOnFailure) { - $this->stop(); - } - } - - foreach ($this->listeners as $listener) { - $listener->$notifyMethod($test, $e, $time); - } - - $this->lastTestFailed = TRUE; - $this->time += $time; - } - - /** - * Adds a failure to the list of failures. - * The passed in exception caused the failure. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - if ($e instanceof PHPUnit_Framework_IncompleteTest) { - $this->notImplemented[] = new PHPUnit_Framework_TestFailure( - $test, $e - ); - - $notifyMethod = 'addIncompleteTest'; - - if ($this->stopOnIncomplete) { - $this->stop(); - } - } - - else if ($e instanceof PHPUnit_Framework_SkippedTest) { - $this->skipped[] = new PHPUnit_Framework_TestFailure($test, $e); - $notifyMethod = 'addSkippedTest'; - - if ($this->stopOnSkipped) { - $this->stop(); - } - } - - else { - $this->failures[] = new PHPUnit_Framework_TestFailure($test, $e); - $notifyMethod = 'addFailure'; - - if ($this->stopOnFailure) { - $this->stop(); - } - } - - foreach ($this->listeners as $listener) { - $listener->$notifyMethod($test, $e, $time); - } - - $this->lastTestFailed = TRUE; - $this->time += $time; - } - - /** - * Adds a deprecated feature notice to the list of deprecated features used during run - * - * @param PHPUnit_Util_DeprecatedFeature $deprecatedFeature - */ - public function addDeprecatedFeature(PHPUnit_Util_DeprecatedFeature $deprecatedFeature) - { - $this->deprecatedFeatures[] = $deprecatedFeature; - } - - /** - * Informs the result that a testsuite will be started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - if ($this->topTestSuite === NULL) { - $this->topTestSuite = $suite; - } - - foreach ($this->listeners as $listener) { - $listener->startTestSuite($suite); - } - } - - /** - * Informs the result that a testsuite was completed. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - foreach ($this->listeners as $listener) { - $listener->endTestSuite($suite); - } - } - - /** - * Informs the result that a test will be started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - $this->lastTestFailed = FALSE; - $this->runTests += count($test); - - foreach ($this->listeners as $listener) { - $listener->startTest($test); - } - } - - /** - * Informs the result that a test was completed. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - foreach ($this->listeners as $listener) { - $listener->endTest($test, $time); - } - - if (!$this->lastTestFailed && $test instanceof PHPUnit_Framework_TestCase) { - $class = get_class($test); - $key = $class . '::' . $test->getName(); - - $this->passed[$key] = array( - 'result' => $test->getResult(), - 'size' => PHPUnit_Util_Test::getSize( - $class, $test->getName(FALSE) - ) - ); - - $this->time += $time; - } - } - - /** - * Returns TRUE if no incomplete test occured. - * - * @return boolean - */ - public function allCompletelyImplemented() - { - return $this->notImplementedCount() == 0; - } - - /** - * Gets the number of incomplete tests. - * - * @return integer - */ - public function notImplementedCount() - { - return count($this->notImplemented); - } - - /** - * Returns an Enumeration for the incomplete tests. - * - * @return array - */ - public function notImplemented() - { - return $this->notImplemented; - } - - /** - * Returns TRUE if no test has been skipped. - * - * @return boolean - * @since Method available since Release 3.0.0 - */ - public function noneSkipped() - { - return $this->skippedCount() == 0; - } - - /** - * Gets the number of skipped tests. - * - * @return integer - * @since Method available since Release 3.0.0 - */ - public function skippedCount() - { - return count($this->skipped); - } - - /** - * Returns an Enumeration for the skipped tests. - * - * @return array - * @since Method available since Release 3.0.0 - */ - public function skipped() - { - return $this->skipped; - } - - /** - * Gets the number of detected errors. - * - * @return integer - */ - public function errorCount() - { - return count($this->errors); - } - - /** - * Returns an Enumeration for the errors. - * - * @return array - */ - public function errors() - { - return $this->errors; - } - - /** - * Returns an Enumeration for the deprecated features used. - * - * @return array - * @since Method available since Release 3.5.7 - */ - public function deprecatedFeatures() - { - return $this->deprecatedFeatures; - } - - /** - * Returns an Enumeration for the deprecated features used. - * - * @return array - * @since Method available since Release 3.5.7 - */ - public function deprecatedFeaturesCount() - { - return count($this->deprecatedFeatures); - } - - /** - * Gets the number of detected failures. - * - * @return integer - */ - public function failureCount() - { - return count($this->failures); - } - - /** - * Returns an Enumeration for the failures. - * - * @return array - */ - public function failures() - { - return $this->failures; - } - - /** - * Returns the names of the tests that have passed. - * - * @return array - * @since Method available since Release 3.4.0 - */ - public function passed() - { - return $this->passed; - } - - /** - * Returns the (top) test suite. - * - * @return PHPUnit_Framework_TestSuite - * @since Method available since Release 3.0.0 - */ - public function topTestSuite() - { - return $this->topTestSuite; - } - - /** - * Returns whether code coverage information should be collected. - * - * @return boolean If code coverage should be collected - * @since Method available since Release 3.2.0 - */ - public function getCollectCodeCoverageInformation() - { - return $this->codeCoverage !== NULL; - } - - /** - * Returns the strict mode configuration option - * - * @return boolean - */ - public function isStrict() - { - return $this->strictMode; - } - - /** - * Runs a TestCase. - * - * @param PHPUnit_Framework_Test $test - */ - public function run(PHPUnit_Framework_Test $test) - { - PHPUnit_Framework_Assert::resetCount(); - - $error = FALSE; - $failure = FALSE; - $incomplete = FALSE; - $skipped = FALSE; - - $this->startTest($test); - - $errorHandlerSet = FALSE; - - if ($this->convertErrorsToExceptions) { - $oldErrorHandler = set_error_handler( - array('PHPUnit_Util_ErrorHandler', 'handleError'), - E_ALL | E_STRICT - ); - - if ($oldErrorHandler === NULL) { - $errorHandlerSet = TRUE; - } else { - restore_error_handler(); - } - } - - if (self::$xdebugLoaded === NULL) { - self::$xdebugLoaded = extension_loaded('xdebug'); - self::$useXdebug = self::$xdebugLoaded; - } - - $useXdebug = self::$useXdebug && - $this->codeCoverage !== NULL && - !$test instanceof PHPUnit_Extensions_SeleniumTestCase && - !$test instanceof PHPUnit_Framework_Warning; - - if ($useXdebug) { - // We need to blacklist test source files when no whitelist is used. - if (!$this->codeCoverage->filter()->hasWhitelist()) { - $classes = $this->getHierarchy(get_class($test), TRUE); - - foreach ($classes as $class) { - $this->codeCoverage->filter()->addFileToBlacklist( - $class->getFileName() - ); - } - } - - $this->codeCoverage->start($test); - } - - $timer = new PHP_Timer; - $timer->start(); - - try { - if (!$test instanceof PHPUnit_Framework_Warning && - $this->strictMode && - extension_loaded('pcntl') && class_exists('PHP_Invoker')) { - switch ($test->getSize()) { - case PHPUnit_Util_Test::SMALL: { - $_timeout = $this->timeoutForSmallTests; - } - break; - - case PHPUnit_Util_Test::MEDIUM: { - $_timeout = $this->timeoutForMediumTests; - } - break; - - case PHPUnit_Util_Test::LARGE: { - $_timeout = $this->timeoutForLargeTests; - } - break; - } - - $invoker = new PHP_Invoker; - $invoker->invoke(array($test, 'runBare'), array(), $_timeout); - } else { - $test->runBare(); - } - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - $failure = TRUE; - - if ($e instanceof PHPUnit_Framework_IncompleteTestError) { - $incomplete = TRUE; - } - - else if ($e instanceof PHPUnit_Framework_SkippedTestError) { - $skipped = TRUE; - } - } - - catch (Exception $e) { - $error = TRUE; - } - - $time = $timer->stop(); - $test->addToAssertionCount(PHPUnit_Framework_Assert::getCount()); - - if ($this->strictMode && $test->getNumAssertions() == 0) { - $incomplete = TRUE; - } - - if ($useXdebug) { - try { - $this->codeCoverage->stop(!$incomplete && !$skipped); - } - - catch (PHP_CodeCoverage_Exception_UnintentionallyCoveredCode $e) { - $this->addFailure( - $test, - new PHPUnit_Framework_UnintentionallyCoveredCodeError( - 'This test executed code that is not listed as code to be covered' - ), - $time - ); - } - - catch (PHP_CodeCoverage_Exception_InvalidCoversTarget $e) { - $this->addFailure( - $test, - new PHPUnit_Framework_InvalidCoversTargetError( - $e->getMessage() - ), - $time - ); - } - - catch (PHP_CodeCoverage_Exception $cce) { - $error = TRUE; - - if (!isset($e)) { - $e = $cce; - } - } - } - - if ($errorHandlerSet === TRUE) { - restore_error_handler(); - } - - if ($error === TRUE) { - $this->addError($test, $e, $time); - } - - else if ($failure === TRUE) { - $this->addFailure($test, $e, $time); - } - - else if ($this->strictMode && $test->getNumAssertions() == 0) { - $this->addFailure( - $test, - new PHPUnit_Framework_IncompleteTestError( - 'This test did not perform any assertions' - ), - $time - ); - } - - else if ($this->strictMode && $test->hasOutput()) { - $this->addFailure( - $test, - new PHPUnit_Framework_OutputError( - sprintf( - 'This test printed output: %s', - $test->getActualOutput() - ) - ), - $time - ); - } - - $this->endTest($test, $time); - } - - /** - * Gets the number of run tests. - * - * @return integer - */ - public function count() - { - return $this->runTests; - } - - /** - * Checks whether the test run should stop. - * - * @return boolean - */ - public function shouldStop() - { - return $this->stop; - } - - /** - * Marks that the test run should stop. - * - */ - public function stop() - { - $this->stop = TRUE; - } - - /** - * Returns the PHP_CodeCoverage object. - * - * @return PHP_CodeCoverage - * @since Method available since Release 3.5.0 - */ - public function getCodeCoverage() - { - return $this->codeCoverage; - } - - /** - * Returns the PHP_CodeCoverage object. - * - * @return PHP_CodeCoverage - * @since Method available since Release 3.6.0 - */ - public function setCodeCoverage(PHP_CodeCoverage $codeCoverage) - { - $this->codeCoverage = $codeCoverage; - } - - /** - * Enables or disables the error-to-exception conversion. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.2.14 - */ - public function convertErrorsToExceptions($flag) - { - if (is_bool($flag)) { - $this->convertErrorsToExceptions = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Returns the error-to-exception conversion setting. - * - * @return boolean - * @since Method available since Release 3.4.0 - */ - public function getConvertErrorsToExceptions() - { - return $this->convertErrorsToExceptions; - } - - /** - * Enables or disables the stopping when an error occurs. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.5.0 - */ - public function stopOnError($flag) - { - if (is_bool($flag)) { - $this->stopOnError = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Enables or disables the stopping when a failure occurs. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.1.0 - */ - public function stopOnFailure($flag) - { - if (is_bool($flag)) { - $this->stopOnFailure = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Enables or disables the strict mode. - * - * When active - * * Tests that do not assert anything will be marked as incomplete. - * * Tests that are incomplete or skipped yield no code coverage. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.5.2 - */ - public function strictMode($flag) - { - if (is_bool($flag)) { - $this->strictMode = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Enables or disables the stopping for incomplete tests. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.5.0 - */ - public function stopOnIncomplete($flag) - { - if (is_bool($flag)) { - $this->stopOnIncomplete = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Enables or disables the stopping for skipped tests. - * - * @param boolean $flag - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.1.0 - */ - public function stopOnSkipped($flag) - { - if (is_bool($flag)) { - $this->stopOnSkipped = $flag; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Returns the time spent running the tests. - * - * @return float - */ - public function time() - { - return $this->time; - } - - /** - * Returns whether the entire test was successful or not. - * - * @return boolean - */ - public function wasSuccessful() - { - return empty($this->errors) && empty($this->failures); - } - - /** - * Sets the timeout for small tests. - * - * @param integer $timeout - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.6.0 - */ - public function setTimeoutForSmallTests($timeout) - { - if (is_integer($timeout)) { - $this->timeoutForSmallTests = $timeout; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); - } - } - - /** - * Sets the timeout for medium tests. - * - * @param integer $timeout - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.6.0 - */ - public function setTimeoutForMediumTests($timeout) - { - if (is_integer($timeout)) { - $this->timeoutForMediumTests = $timeout; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); - } - } - - /** - * Sets the timeout for large tests. - * - * @param integer $timeout - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.6.0 - */ - public function setTimeoutForLargeTests($timeout) - { - if (is_integer($timeout)) { - $this->timeoutForLargeTests = $timeout; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'integer'); - } - } - - /** - * Returns the class hierarchy for a given class. - * - * @param string $className - * @param boolean $asReflectionObjects - * @return array - */ - protected function getHierarchy($className, $asReflectionObjects = FALSE) - { - if ($asReflectionObjects) { - $classes = array(new ReflectionClass($className)); - } else { - $classes = array($className); - } - - $done = FALSE; - - while (!$done) { - if ($asReflectionObjects) { - $class = new ReflectionClass( - $classes[count($classes)-1]->getName() - ); - } else { - $class = new ReflectionClass($classes[count($classes)-1]); - } - - $parent = $class->getParentClass(); - - if ($parent !== FALSE) { - if ($asReflectionObjects) { - $classes[] = $parent; - } else { - $classes[] = $parent->getName(); - } - } else { - $done = TRUE; - } - } - - return $classes; - } -} diff --git a/PHPUnit/Framework/TestSuite.php b/PHPUnit/Framework/TestSuite.php deleted file mode 100644 index 05c1dc982f7..00000000000 --- a/PHPUnit/Framework/TestSuite.php +++ /dev/null @@ -1,914 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A TestSuite is a composite of Tests. It runs a collection of test cases. - * - * Here is an example using the dynamic test definition. - * - * - * addTest(new MathTest('testPass')); - * ?> - * - * - * Alternatively, a TestSuite can extract the tests to be run automatically. - * To do so you pass a ReflectionClass instance for your - * PHPUnit_Framework_TestCase class to the PHPUnit_Framework_TestSuite - * constructor. - * - * - * - * - * - * This constructor creates a suite with all the methods starting with - * "test" that take no arguments. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_TestSuite implements PHPUnit_Framework_Test, PHPUnit_Framework_SelfDescribing, IteratorAggregate -{ - /** - * Enable or disable the backup and restoration of the $GLOBALS array. - * - * @var boolean - */ - protected $backupGlobals = NULL; - - /** - * Enable or disable the backup and restoration of static attributes. - * - * @var boolean - */ - protected $backupStaticAttributes = NULL; - - protected $runTestInSeparateProcess = FALSE; - - /** - * The name of the test suite. - * - * @var string - */ - protected $name = ''; - - /** - * The test groups of the test suite. - * - * @var array - */ - protected $groups = array(); - - /** - * The tests in the test suite. - * - * @var array - */ - protected $tests = array(); - - /** - * The number of tests in the test suite. - * - * @var integer - */ - protected $numTests = -1; - - /** - * @var boolean - */ - protected $testCase = FALSE; - - /** - * @var PHPUnit_Runner_Filter_Factory - */ - private $iteratorFilter = NULL; - - /** - * Constructs a new TestSuite: - * - * - PHPUnit_Framework_TestSuite() constructs an empty TestSuite. - * - * - PHPUnit_Framework_TestSuite(ReflectionClass) constructs a - * TestSuite from the given class. - * - * - PHPUnit_Framework_TestSuite(ReflectionClass, String) - * constructs a TestSuite from the given class with the given - * name. - * - * - PHPUnit_Framework_TestSuite(String) either constructs a - * TestSuite from the given class (if the passed string is the - * name of an existing class) or constructs an empty TestSuite - * with the given name. - * - * @param mixed $theClass - * @param string $name - * @throws PHPUnit_Framework_Exception - */ - public function __construct($theClass = '', $name = '') - { - $argumentsValid = FALSE; - - if (is_object($theClass) && - $theClass instanceof ReflectionClass) { - $argumentsValid = TRUE; - } - - else if (is_string($theClass) && - $theClass !== '' && - class_exists($theClass, FALSE)) { - $argumentsValid = TRUE; - - if ($name == '') { - $name = $theClass; - } - - $theClass = new ReflectionClass($theClass); - } - - else if (is_string($theClass)) { - $this->setName($theClass); - return; - } - - if (!$argumentsValid) { - throw new PHPUnit_Framework_Exception; - } - - if (!$theClass->isSubclassOf('PHPUnit_Framework_TestCase')) { - throw new PHPUnit_Framework_Exception( - 'Class "' . $theClass->name . '" does not extend PHPUnit_Framework_TestCase.' - ); - } - - if ($name != '') { - $this->setName($name); - } else { - $this->setName($theClass->getName()); - } - - $constructor = $theClass->getConstructor(); - - if ($constructor !== NULL && - !$constructor->isPublic()) { - $this->addTest( - self::warning( - sprintf( - 'Class "%s" has no public constructor.', - - $theClass->getName() - ) - ) - ); - - return; - } - - foreach ($theClass->getMethods() as $method) { - $this->addTestMethod($theClass, $method); - } - - if (empty($this->tests)) { - $this->addTest( - self::warning( - sprintf( - 'No tests found in class "%s".', - - $theClass->getName() - ) - ) - ); - } - - $this->testCase = TRUE; - } - - /** - * Returns a string representation of the test suite. - * - * @return string - */ - public function toString() - { - return $this->getName(); - } - - /** - * Adds a test to the suite. - * - * @param PHPUnit_Framework_Test $test - * @param array $groups - */ - public function addTest(PHPUnit_Framework_Test $test, $groups = array()) - { - $class = new ReflectionClass($test); - - if (!$class->isAbstract()) { - $this->tests[] = $test; - $this->numTests = -1; - - if ($test instanceof PHPUnit_Framework_TestSuite && - empty($groups)) { - $groups = $test->getGroups(); - } - - if (empty($groups)) { - $groups = array('__nogroup__'); - } - - foreach ($groups as $group) { - if (!isset($this->groups[$group])) { - $this->groups[$group] = array($test); - } else { - $this->groups[$group][] = $test; - } - } - } - } - - /** - * Adds the tests from the given class to the suite. - * - * @param mixed $testClass - * @throws PHPUnit_Framework_Exception - */ - public function addTestSuite($testClass) - { - if (is_string($testClass) && class_exists($testClass)) { - $testClass = new ReflectionClass($testClass); - } - - if (!is_object($testClass)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'class name or object' - ); - } - - if ($testClass instanceof PHPUnit_Framework_TestSuite) { - $this->addTest($testClass); - } - - else if ($testClass instanceof ReflectionClass) { - $suiteMethod = FALSE; - - if (!$testClass->isAbstract()) { - if ($testClass->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) { - $method = $testClass->getMethod( - PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME - ); - - if ($method->isStatic()) { - $this->addTest( - $method->invoke(NULL, $testClass->getName()) - ); - - $suiteMethod = TRUE; - } - } - } - - if (!$suiteMethod && !$testClass->isAbstract()) { - $this->addTest(new PHPUnit_Framework_TestSuite($testClass)); - } - } - - else { - throw new PHPUnit_Framework_Exception; - } - } - - /** - * Wraps both addTest() and addTestSuite - * as well as the separate import statements for the user's convenience. - * - * If the named file cannot be read or there are no new tests that can be - * added, a PHPUnit_Framework_Warning will be created instead, - * leaving the current test run untouched. - * - * @param string $filename - * @param array $phptOptions Array with ini settings for the php instance - * run, key being the name if the setting, - * value the ini value. - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 2.3.0 - * @author Stefano F. Rausch - */ - public function addTestFile($filename, $phptOptions = array()) - { - if (!is_string($filename)) { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string'); - } - - if (file_exists($filename) && substr($filename, -5) == '.phpt') { - $this->addTest( - new PHPUnit_Extensions_PhptTestCase($filename, $phptOptions) - ); - - return; - } - - $classes = get_declared_classes(); - $filename = PHPUnit_Util_Fileloader::checkAndLoad($filename); - $newClasses = array_values(array_diff(get_declared_classes(), $classes)); - $baseName = str_replace('.php', '', basename($filename)); - - foreach ($newClasses as $className) { - if (substr($className, 0 - strlen($baseName)) == $baseName) { - $class = new ReflectionClass($className); - - if ($class->getFileName() == $filename) { - $newClasses = array($className); - break; - } - } - } - - foreach ($newClasses as $className) { - $class = new ReflectionClass($className); - - if (!$class->isAbstract()) { - if ($class->hasMethod(PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME)) { - $method = $class->getMethod( - PHPUnit_Runner_BaseTestRunner::SUITE_METHODNAME - ); - - if ($method->isStatic()) { - $this->addTest($method->invoke(NULL, $className)); - } - } - - else if ($class->implementsInterface('PHPUnit_Framework_Test')) { - $this->addTestSuite($class); - } - } - } - - $this->numTests = -1; - } - - /** - * Wrapper for addTestFile() that adds multiple test files. - * - * @param array|Iterator $filenames - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 2.3.0 - */ - public function addTestFiles($filenames) - { - if (!(is_array($filenames) || - (is_object($filenames) && $filenames instanceof Iterator))) { - throw PHPUnit_Util_InvalidArgumentHelper::factory( - 1, 'array or iterator' - ); - } - - foreach ($filenames as $filename) { - $this->addTestFile((string)$filename); - } - } - - /** - * Counts the number of test cases that will be run by this test. - * - * @return integer - */ - public function count() - { - $numTests = 0; - - foreach ($this as $test) { - $numTests += count($test); - } - - return $numTests; - } - - /** - * @param ReflectionClass $theClass - * @param string $name - * @return PHPUnit_Framework_Test - * @throws PHPUnit_Framework_Exception - */ - public static function createTest(ReflectionClass $theClass, $name) - { - $className = $theClass->getName(); - - if (!$theClass->isInstantiable()) { - return self::warning( - sprintf('Cannot instantiate class "%s".', $className) - ); - } - - $backupSettings = PHPUnit_Util_Test::getBackupSettings( - $className, $name - ); - $preserveGlobalState = PHPUnit_Util_Test::getPreserveGlobalStateSettings( - $className, $name - ); - $runTestInSeparateProcess = PHPUnit_Util_Test::getProcessIsolationSettings( - $className, $name - ); - - $constructor = $theClass->getConstructor(); - - if ($constructor !== NULL) { - $parameters = $constructor->getParameters(); - - // TestCase() or TestCase($name) - if (count($parameters) < 2) { - $test = new $className; - } - - // TestCase($name, $data) - else { - try { - $data = PHPUnit_Util_Test::getProvidedData( - $className, $name - ); - } - - catch (Exception $e) { - $message = sprintf( - 'The data provider specified for %s::%s is invalid.', - $className, - $name - ); - - $_message = $e->getMessage(); - - if (!empty($_message)) { - $message .= "\n" . $_message; - } - - $data = self::warning($message); - } - - // Test method with @dataProvider. - if (isset($data)) { - $test = new PHPUnit_Framework_TestSuite_DataProvider( - $className . '::' . $name - ); - - if (empty($data)) { - $data = self::warning( - sprintf( - 'No tests found in suite "%s".', - $test->getName() - ) - ); - } - - $groups = PHPUnit_Util_Test::getGroups($className, $name); - - if ($data instanceof PHPUnit_Framework_Warning) { - $test->addTest($data, $groups); - } - - else { - foreach ($data as $_dataName => $_data) { - $_test = new $className($name, $_data, $_dataName); - - if ($runTestInSeparateProcess) { - $_test->setRunTestInSeparateProcess(TRUE); - - if ($preserveGlobalState !== NULL) { - $_test->setPreserveGlobalState($preserveGlobalState); - } - } - - if ($backupSettings['backupGlobals'] !== NULL) { - $_test->setBackupGlobals( - $backupSettings['backupGlobals'] - ); - } - - if ($backupSettings['backupStaticAttributes'] !== NULL) { - $_test->setBackupStaticAttributes( - $backupSettings['backupStaticAttributes'] - ); - } - - $test->addTest($_test, $groups); - } - } - } - - else { - $test = new $className; - } - } - } - - if (!isset($test)) { - throw new PHPUnit_Framework_Exception('No valid test provided.'); - } - - if ($test instanceof PHPUnit_Framework_TestCase) { - $test->setName($name); - - if ($runTestInSeparateProcess) { - $test->setRunTestInSeparateProcess(TRUE); - - if ($preserveGlobalState !== NULL) { - $test->setPreserveGlobalState($preserveGlobalState); - } - } - - if ($backupSettings['backupGlobals'] !== NULL) { - $test->setBackupGlobals($backupSettings['backupGlobals']); - } - - if ($backupSettings['backupStaticAttributes'] !== NULL) { - $test->setBackupStaticAttributes( - $backupSettings['backupStaticAttributes'] - ); - } - } - - return $test; - } - - /** - * Creates a default TestResult object. - * - * @return PHPUnit_Framework_TestResult - */ - protected function createResult() - { - return new PHPUnit_Framework_TestResult; - } - - /** - * Returns the name of the suite. - * - * @return string - */ - public function getName() - { - return $this->name; - } - - /** - * Returns the test groups of the suite. - * - * @return array - * @since Method available since Release 3.2.0 - */ - public function getGroups() - { - return array_keys($this->groups); - } - - public function getGroupDetails() { - return $this->groups; - } - - /** - * Runs the tests and collects their result in a TestResult. - * - * @param PHPUnit_Framework_TestResult $result - * @param mixed $filter - * @param array $groups - * @param array $excludeGroups - * @param boolean $processIsolation - * @return PHPUnit_Framework_TestResult - * @throws PHPUnit_Framework_Exception - */ - public function run(PHPUnit_Framework_TestResult $result = NULL) - { - if ($result === NULL) { - $result = $this->createResult(); - } - - if (count($this) == 0) { - return $result; - } - - $result->startTestSuite($this); - - try { - $this->setUp(); - - if ($this->testCase && - // Some extensions use test names that are not classes; - // The method_exists() triggers an autoload call that causes issues with die()ing autoloaders. - class_exists($this->name, false) && - method_exists($this->name, 'setUpBeforeClass')) { - call_user_func(array($this->name, 'setUpBeforeClass')); - } - } - - catch (PHPUnit_Framework_SkippedTestSuiteError $e) { - $numTests = count($this); - - for ($i = 0; $i < $numTests; $i++) { - $result->addFailure($this, $e, 0); - } - - return $result; - } - - catch (Exception $e) { - $numTests = count($this); - - for ($i = 0; $i < $numTests; $i++) { - $result->addError($this, $e, 0); - } - - return $result; - } - - foreach ($this as $test) { - if ($result->shouldStop()) { - break; - } - - if ($test instanceof PHPUnit_Framework_TestCase || - $test instanceof PHPUnit_Framework_TestSuite) { - $test->setBackupGlobals($this->backupGlobals); - $test->setBackupStaticAttributes($this->backupStaticAttributes); - $test->setRunTestInSeparateProcess($this->runTestInSeparateProcess); - } - - - $test->run($result); - } - - if ($this->testCase && - // Some extensions use test names that are not classes; - // The method_exists() triggers an autoload call that causes issues with die()ing autoloaders. - class_exists($this->name, false) && - method_exists($this->name, 'tearDownAfterClass')) { - call_user_func(array($this->name, 'tearDownAfterClass')); - } - - $this->tearDown(); - - $result->endTestSuite($this); - - return $result; - } - - /** - * @param boolean $runTestInSeparateProcess - * @throws InvalidArgumentException - * @since Method available since Release 3.7.0 - */ - public function setRunTestInSeparateProcess($runTestInSeparateProcess) - { - if (is_bool($runTestInSeparateProcess)) { - $this->runTestInSeparateProcess = $runTestInSeparateProcess; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } - - /** - * Runs a test. - * - * @deprecated - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_TestResult $result - */ - public function runTest(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result) - { - $test->run($result); - } - - /** - * Sets the name of the suite. - * - * @param string - */ - public function setName($name) - { - $this->name = $name; - } - - /** - * Returns the test at the given index. - * - * @param integer - * @return PHPUnit_Framework_Test - */ - public function testAt($index) - { - if (isset($this->tests[$index])) { - return $this->tests[$index]; - } else { - return FALSE; - } - } - - /** - * Returns the tests as an enumeration. - * - * @return array - */ - public function tests() - { - return $this->tests; - } - - /** - * Mark the test suite as skipped. - * - * @param string $message - * @throws PHPUnit_Framework_SkippedTestSuiteError - * @since Method available since Release 3.0.0 - */ - public function markTestSuiteSkipped($message = '') - { - throw new PHPUnit_Framework_SkippedTestSuiteError($message); - } - - /** - * @param ReflectionClass $class - * @param ReflectionMethod $method - */ - protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method) - { - $name = $method->getName(); - - if ($this->isPublicTestMethod($method)) { - $test = self::createTest($class, $name); - - if ($test instanceof PHPUnit_Framework_TestCase || - $test instanceof PHPUnit_Framework_TestSuite_DataProvider) { - $test->setDependencies( - PHPUnit_Util_Test::getDependencies($class->getName(), $name) - ); - } - - $this->addTest($test, PHPUnit_Util_Test::getGroups( - $class->getName(), $name) - ); - } - - else if ($this->isTestMethod($method)) { - $this->addTest( - self::warning( - sprintf( - 'Test method "%s" in test class "%s" is not public.', - $name, - $class->getName() - ) - ) - ); - } - } - - /** - * @param ReflectionMethod $method - * @return boolean - */ - public static function isPublicTestMethod(ReflectionMethod $method) - { - return (self::isTestMethod($method) && $method->isPublic()); - } - - /** - * @param ReflectionMethod $method - * @return boolean - */ - public static function isTestMethod(ReflectionMethod $method) - { - if (strpos($method->name, 'test') === 0) { - return TRUE; - } - - // @scenario on TestCase::testMethod() - // @test on TestCase::testMethod() - return strpos($method->getDocComment(), '@test') !== FALSE || - strpos($method->getDocComment(), '@scenario') !== FALSE; - } - - /** - * @param string $message - * @return PHPUnit_Framework_Warning - */ - protected static function warning($message) - { - return new PHPUnit_Framework_Warning($message); - } - - /** - * @param boolean $backupGlobals - * @since Method available since Release 3.3.0 - */ - public function setBackupGlobals($backupGlobals) - { - if (is_null($this->backupGlobals) && is_bool($backupGlobals)) { - $this->backupGlobals = $backupGlobals; - } - } - - /** - * @param boolean $backupStaticAttributes - * @since Method available since Release 3.4.0 - */ - public function setBackupStaticAttributes($backupStaticAttributes) - { - if (is_null($this->backupStaticAttributes) && - is_bool($backupStaticAttributes)) { - $this->backupStaticAttributes = $backupStaticAttributes; - } - } - - /** - * Returns an iterator for this test suite. - * - * @return RecursiveIteratorIterator - * @since Method available since Release 3.1.0 - */ - public function getIterator() - { - $iterator = new PHPUnit_Util_TestSuiteIterator($this); - - if ($this->iteratorFilter !== NULL) { - $iterator = $this->iteratorFilter->factory($iterator, $this); - } - - return $iterator; - } - - public function injectFilter(PHPUnit_Runner_Filter_Factory $filter) { - $this->iteratorFilter = $filter; - foreach ($this as $test) { - if ($test instanceof PHPUnit_Framework_TestSuite) { - $test->injectFilter($filter); - } - } - } - - /** - * Template Method that is called before the tests - * of this test suite are run. - * - * @since Method available since Release 3.1.0 - */ - protected function setUp() - { - } - - /** - * Template Method that is called after the tests - * of this test suite have finished running. - * - * @since Method available since Release 3.1.0 - */ - protected function tearDown() - { - } -} diff --git a/PHPUnit/Framework/TestSuite/DataProvider.php b/PHPUnit/Framework/TestSuite/DataProvider.php deleted file mode 100644 index b0ebf10e1e0..00000000000 --- a/PHPUnit/Framework/TestSuite/DataProvider.php +++ /dev/null @@ -1,70 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework_TestSuite - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Framework_TestSuite - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Framework_TestSuite_DataProvider extends PHPUnit_Framework_TestSuite -{ - /** - * Sets the dependencies of a TestCase. - * - * @param array $dependencies - */ - public function setDependencies(array $dependencies) - { - foreach ($this->tests as $test) { - $test->setDependencies($dependencies); - } - } -} diff --git a/PHPUnit/Framework/UnintentionallyCoveredCodeError.php b/PHPUnit/Framework/UnintentionallyCoveredCodeError.php deleted file mode 100644 index 403064e508c..00000000000 --- a/PHPUnit/Framework/UnintentionallyCoveredCodeError.php +++ /dev/null @@ -1,60 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * Extension to PHPUnit_Framework_AssertionFailedError to mark the special - * case of a test test that unintentionally covers code. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Framework_UnintentionallyCoveredCodeError extends PHPUnit_Framework_AssertionFailedError -{ -} diff --git a/PHPUnit/Framework/Warning.php b/PHPUnit/Framework/Warning.php deleted file mode 100644 index b2516e7b4e4..00000000000 --- a/PHPUnit/Framework/Warning.php +++ /dev/null @@ -1,125 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A warning. - * - * @package PHPUnit - * @subpackage Framework - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Framework_Warning extends PHPUnit_Framework_TestCase -{ - /** - * @var string - */ - protected $message = ''; - - /** - * @var boolean - */ - protected $backupGlobals = FALSE; - - /** - * @var boolean - */ - protected $backupStaticAttributes = FALSE; - - /** - * @var boolean - */ - protected $runTestInSeparateProcess = FALSE; - - /** - * @var boolean - */ - protected $useErrorHandler = FALSE; - - /** - * @var boolean - */ - protected $useOutputBuffering = FALSE; - - /** - * @param string $message - */ - public function __construct($message = '') - { - $this->message = $message; - parent::__construct('Warning'); - } - - /** - * @throws PHPUnit_Framework_Exception - */ - protected function runTest() - { - $this->fail($this->message); - } - - /** - * @return string - * @since Method available since Release 3.0.0 - */ - public function getMessage() - { - return $this->message; - } - - /** - * Returns a string representation of the test case. - * - * @return string - * @since Method available since Release 3.4.0 - */ - public function toString() - { - return 'Warning'; - } -} diff --git a/PHPUnit/Runner/BaseTestRunner.php b/PHPUnit/Runner/BaseTestRunner.php deleted file mode 100644 index d6663f6ac1e..00000000000 --- a/PHPUnit/Runner/BaseTestRunner.php +++ /dev/null @@ -1,189 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Base class for all test runners. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -abstract class PHPUnit_Runner_BaseTestRunner -{ - const STATUS_PASSED = 0; - const STATUS_SKIPPED = 1; - const STATUS_INCOMPLETE = 2; - const STATUS_FAILURE = 3; - const STATUS_ERROR = 4; - const SUITE_METHODNAME = 'suite'; - - /** - * Returns the loader to be used. - * - * @return PHPUnit_Runner_TestSuiteLoader - */ - public function getLoader() - { - return new PHPUnit_Runner_StandardTestSuiteLoader; - } - - /** - * Returns the Test corresponding to the given suite. - * This is a template method, subclasses override - * the runFailed() and clearStatus() methods. - * - * @param string $suiteClassName - * @param string $suiteClassFile - * @param mixed $suffixes - * @return PHPUnit_Framework_Test - */ - public function getTest($suiteClassName, $suiteClassFile = '', $suffixes = '') - { - if (is_dir($suiteClassName) && - !is_file($suiteClassName . '.php') && empty($suiteClassFile)) { - $facade = new File_Iterator_Facade; - $files = $facade->getFilesAsArray( - $suiteClassName, $suffixes - ); - - $suite = new PHPUnit_Framework_TestSuite($suiteClassName); - $suite->addTestFiles($files); - - return $suite; - } - - try { - $testClass = $this->loadSuiteClass( - $suiteClassName, $suiteClassFile - ); - } - - catch (Exception $e) { - $this->runFailed($e->getMessage()); - return NULL; - } - - try { - $suiteMethod = $testClass->getMethod(self::SUITE_METHODNAME); - - if (!$suiteMethod->isStatic()) { - $this->runFailed( - 'suite() method must be static.' - ); - - return NULL; - } - - try { - $test = $suiteMethod->invoke(NULL, $testClass->getName()); - } - - catch (ReflectionException $e) { - $this->runFailed( - sprintf( - "Failed to invoke suite() method.\n%s", - - $e->getMessage() - ) - ); - - return NULL; - } - } - - catch (ReflectionException $e) { - try { - $test = new PHPUnit_Framework_TestSuite($testClass); - } - - catch (PHPUnit_Framework_Exception $e) { - $test = new PHPUnit_Framework_TestSuite; - $test->setName($suiteClassName); - } - } - - $this->clearStatus(); - - return $test; - } - - /** - * Returns the loaded ReflectionClass for a suite name. - * - * @param string $suiteClassName - * @param string $suiteClassFile - * @return ReflectionClass - */ - protected function loadSuiteClass($suiteClassName, $suiteClassFile = '') - { - $loader = $this->getLoader(); - - if ($loader instanceof PHPUnit_Runner_StandardTestSuiteLoader) { - return $loader->load($suiteClassName, $suiteClassFile); - } else { - return $loader->load($suiteClassName, $suiteClassFile); - } - } - - /** - * Clears the status message. - * - */ - protected function clearStatus() - { - } - - /** - * Override to define how to handle a failed loading of - * a test suite. - * - * @param string $message - */ - abstract protected function runFailed($message); -} diff --git a/PHPUnit/Runner/Filter/Factory.php b/PHPUnit/Runner/Filter/Factory.php deleted file mode 100644 index da8172a2407..00000000000 --- a/PHPUnit/Runner/Filter/Factory.php +++ /dev/null @@ -1,92 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Runner_Filter_Factory -{ - /** - * @var array - */ - private $filters = array(); - - /** - * @param ReflectionClass $filter - * @param mixed $args - */ - public function addFilter(ReflectionClass $filter, $args) - { - if (!$filter->isSubclassOf('RecursiveFilterIterator')) { - throw new InvalidArgumentException( - sprintf( - 'Class "%s" does not extend RecursiveFilterIterator', - $filter->name - ) - ); - } - - $this->filters[] = array($filter, $args); - } - - /** - * @return FilterIterator - */ - public function factory(Iterator $iterator, PHPUnit_Framework_TestSuite $suite) - { - foreach ($this->filters as $filter) { - list($class, $args) = $filter; - $iterator = $class->newInstance($iterator, $args, $suite); - } - - return $iterator; - } -} diff --git a/PHPUnit/Runner/Filter/Group.php b/PHPUnit/Runner/Filter/Group.php deleted file mode 100644 index 120b2f15951..00000000000 --- a/PHPUnit/Runner/Filter/Group.php +++ /dev/null @@ -1,98 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -abstract class PHPUnit_Runner_Filter_GroupFilterIterator extends RecursiveFilterIterator -{ - /** - * @var array - */ - protected $groupTests = array(); - - /** - * @param RecursiveIterator $iterator - * @param array $groups - * @param PHPUnit_Framework_TestSuite $suite - */ - public function __construct(RecursiveIterator $iterator, array $groups, PHPUnit_Framework_TestSuite $suite) - { - parent::__construct($iterator); - - foreach ($suite->getGroupDetails() as $group => $tests) { - if (in_array($group, $groups)) { - $testHashes = array_map( - function($test) { return spl_object_hash($test); }, - $tests - ); - - $this->groupTests = array_merge($this->groupTests, $testHashes); - } - } - } - - /** - * @return boolean - */ - public function accept() - { - $test = $this->getInnerIterator()->current(); - - if ($test instanceof PHPUnit_Framework_TestSuite) { - return TRUE; - } - - return $this->doAccept(spl_object_hash($test)); - } - - abstract protected function doAccept($hash); -} diff --git a/PHPUnit/Runner/Filter/Group/Exclude.php b/PHPUnit/Runner/Filter/Group/Exclude.php deleted file mode 100644 index c22eb5a88ef..00000000000 --- a/PHPUnit/Runner/Filter/Group/Exclude.php +++ /dev/null @@ -1,61 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Runner_Filter_Group_Exclude extends PHPUnit_Runner_Filter_GroupFilterIterator -{ - protected function doAccept($hash) - { - return !in_array($hash, $this->groupTests); - } -} diff --git a/PHPUnit/Runner/Filter/Group/Include.php b/PHPUnit/Runner/Filter/Group/Include.php deleted file mode 100644 index a05574f2298..00000000000 --- a/PHPUnit/Runner/Filter/Group/Include.php +++ /dev/null @@ -1,61 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Runner_Filter_Group_Include extends PHPUnit_Runner_Filter_GroupFilterIterator -{ - protected function doAccept($hash) - { - return in_array($hash, $this->groupTests); - } -} diff --git a/PHPUnit/Runner/Filter/Test.php b/PHPUnit/Runner/Filter/Test.php deleted file mode 100644 index 289c8917d09..00000000000 --- a/PHPUnit/Runner/Filter/Test.php +++ /dev/null @@ -1,93 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -/** - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class PHPUnit_Runner_Filter_Test extends RecursiveFilterIterator -{ - /** - * @var string - */ - protected $filter = NULL; - - /** - * @param RecursiveIterator $iterator - * @param string $filter - */ - public function __construct(RecursiveIterator $iterator, $filter) - { - parent::__construct($iterator); - $this->filter = $filter; - } - - /** - * @return boolean - */ - public function accept() - { - $test = $this->getInnerIterator()->current(); - - if ($test instanceof PHPUnit_Framework_TestSuite) { - return TRUE; - } - - $tmp = PHPUnit_Util_Test::describe($test, FALSE); - - if ($tmp[0] != '') { - $name = join('::', $tmp); - } else { - $name = $tmp[1]; - } - - return preg_match($this->filter, $name); - } -} diff --git a/PHPUnit/Runner/StandardTestSuiteLoader.php b/PHPUnit/Runner/StandardTestSuiteLoader.php deleted file mode 100644 index b65fa28e8b1..00000000000 --- a/PHPUnit/Runner/StandardTestSuiteLoader.php +++ /dev/null @@ -1,157 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * The standard test suite loader. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Runner_StandardTestSuiteLoader implements PHPUnit_Runner_TestSuiteLoader -{ - /** - * @param string $suiteClassName - * @param string $suiteClassFile - * @return ReflectionClass - * @throws PHPUnit_Framework_Exception - */ - public function load($suiteClassName, $suiteClassFile = '') - { - $suiteClassName = str_replace('.php', '', $suiteClassName); - - if (empty($suiteClassFile)) { - $suiteClassFile = PHPUnit_Util_Filesystem::classNameToFilename( - $suiteClassName - ); - } - - if (!class_exists($suiteClassName, FALSE)) { - $loadedClasses = get_declared_classes(); - - $filename = PHPUnit_Util_Fileloader::checkAndLoad($suiteClassFile); - - $loadedClasses = array_values( - array_diff(get_declared_classes(), $loadedClasses) - ); - } - - if (!class_exists($suiteClassName, FALSE) && !empty($loadedClasses)) { - $offset = 0 - strlen($suiteClassName); - - foreach ($loadedClasses as $loadedClass) { - $class = new ReflectionClass($loadedClass); - if (substr($loadedClass, $offset) === $suiteClassName && - $class->getFileName() == $filename) { - $suiteClassName = $loadedClass; - break; - } - } - } - - if (!class_exists($suiteClassName, FALSE) && !empty($loadedClasses)) { - $testCaseClass = 'PHPUnit_Framework_TestCase'; - - foreach ($loadedClasses as $loadedClass) { - $class = new ReflectionClass($loadedClass); - $classFile = $class->getFileName(); - - if ($class->isSubclassOf($testCaseClass) && - !$class->isAbstract()) { - $suiteClassName = $loadedClass; - $testCaseClass = $loadedClass; - - if ($classFile == realpath($suiteClassFile)) { - break; - } - } - - if ($class->hasMethod('suite')) { - $method = $class->getMethod('suite'); - - if (!$method->isAbstract() && - $method->isPublic() && - $method->isStatic()) { - $suiteClassName = $loadedClass; - - if ($classFile == realpath($suiteClassFile)) { - break; - } - } - } - } - } - - if (class_exists($suiteClassName, FALSE)) { - $class = new ReflectionClass($suiteClassName); - - if ($class->getFileName() == realpath($suiteClassFile)) { - return $class; - } - } - - throw new PHPUnit_Framework_Exception( - sprintf( - "Class '%s' could not be found in '%s'.", - - $suiteClassName, - $suiteClassFile - ) - ); - } - - /** - * @param ReflectionClass $aClass - * @return ReflectionClass - */ - public function reload(ReflectionClass $aClass) - { - return $aClass; - } -} diff --git a/PHPUnit/Runner/TestSuiteLoader.php b/PHPUnit/Runner/TestSuiteLoader.php deleted file mode 100644 index 43d6a5d4617..00000000000 --- a/PHPUnit/Runner/TestSuiteLoader.php +++ /dev/null @@ -1,71 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * An interface to define how a test suite should be loaded. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 2.0.0 - */ -interface PHPUnit_Runner_TestSuiteLoader -{ - /** - * @param string $suiteClassName - * @param string $suiteClassFile - * @return ReflectionClass - */ - public function load($suiteClassName, $suiteClassFile = ''); - - /** - * @param ReflectionClass $aClass - * @return ReflectionClass - */ - public function reload(ReflectionClass $aClass); -} diff --git a/PHPUnit/Runner/Version.php b/PHPUnit/Runner/Version.php deleted file mode 100644 index b0783a2090e..00000000000 --- a/PHPUnit/Runner/Version.php +++ /dev/null @@ -1,83 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * This class defines the current version of PHPUnit. - * - * @package PHPUnit - * @subpackage Runner - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Runner_Version -{ - private static $version; - - /** - * Returns the current version of PHPUnit. - * - * @return string - */ - public static function id() - { - if (self::$version === NULL) { - $version = new SebastianBergmann\Version('3.8', __DIR__); - self::$version = $version->getVersion(); - } - - return self::$version; - } - - /** - * @return string - */ - public static function getVersionString() - { - return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann.'; - } -} diff --git a/PHPUnit/TextUI/Command.php b/PHPUnit/TextUI/Command.php deleted file mode 100644 index c63ea9ee276..00000000000 --- a/PHPUnit/TextUI/Command.php +++ /dev/null @@ -1,899 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * A TestRunner for the Command Line Interface (CLI) - * PHP SAPI Module. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_TextUI_Command -{ - /** - * @var array - */ - protected $arguments = array( - 'listGroups' => FALSE, - 'loader' => NULL, - 'useDefaultConfiguration' => TRUE - ); - - /** - * @var array - */ - protected $options = array(); - - /** - * @var array - */ - protected $longOptions = array( - 'colors' => NULL, - 'bootstrap=' => NULL, - 'configuration=' => NULL, - 'coverage-html=' => NULL, - 'coverage-clover=' => NULL, - 'coverage-php=' => NULL, - 'coverage-text==' => NULL, - 'debug' => NULL, - 'exclude-group=' => NULL, - 'filter=' => NULL, - 'testsuite=' => NULL, - 'group=' => NULL, - 'help' => NULL, - 'include-path=' => NULL, - 'list-groups' => NULL, - 'loader=' => NULL, - 'log-json=' => NULL, - 'log-junit=' => NULL, - 'log-tap=' => NULL, - 'process-isolation' => NULL, - 'repeat=' => NULL, - 'stderr' => NULL, - 'stop-on-error' => NULL, - 'stop-on-failure' => NULL, - 'stop-on-incomplete' => NULL, - 'stop-on-skipped' => NULL, - 'strict' => NULL, - 'tap' => NULL, - 'testdox' => NULL, - 'testdox-html=' => NULL, - 'testdox-text=' => NULL, - 'test-suffix=' => NULL, - 'no-configuration' => NULL, - 'no-globals-backup' => NULL, - 'printer=' => NULL, - 'static-backup' => NULL, - 'verbose' => NULL, - 'version' => NULL - ); - - /** - * @var array - */ - protected $missingExtensions = array(); - - /** - * @param boolean $exit - */ - public static function main($exit = TRUE) - { - $command = new PHPUnit_TextUI_Command; - return $command->run($_SERVER['argv'], $exit); - } - - /** - * @param array $argv - * @param boolean $exit - */ - public function run(array $argv, $exit = TRUE) - { - $this->handleArguments($argv); - - $runner = $this->createRunner(); - - if (is_object($this->arguments['test']) && - $this->arguments['test'] instanceof PHPUnit_Framework_Test) { - $suite = $this->arguments['test']; - } else { - $suite = $runner->getTest( - $this->arguments['test'], - $this->arguments['testFile'], - $this->arguments['testSuffixes'] - ); - } - - if ($this->arguments['listGroups']) { - PHPUnit_TextUI_TestRunner::printVersionString(); - - print "Available test group(s):\n"; - - $groups = $suite->getGroups(); - sort($groups); - - foreach ($groups as $group) { - print " - $group\n"; - } - - if ($exit) { - exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); - } else { - return PHPUnit_TextUI_TestRunner::SUCCESS_EXIT; - } - } - - unset($this->arguments['test']); - unset($this->arguments['testFile']); - - try { - $result = $runner->doRun($suite, $this->arguments); - } - - catch (PHPUnit_Framework_Exception $e) { - print $e->getMessage() . "\n"; - } - - $ret = PHPUnit_TextUI_TestRunner::FAILURE_EXIT; - - if (isset($result) && $result->wasSuccessful()) { - $ret = PHPUnit_TextUI_TestRunner::SUCCESS_EXIT; - } - - else if (!isset($result) || $result->errorCount() > 0) { - $ret = PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT; - } - - if ($exit) { - exit($ret); - } else { - return $ret; - } - } - - /** - * Create a TestRunner, override in subclasses. - * - * @return PHPUnit_TextUI_TestRunner - * @since Method available since Release 3.6.0 - */ - protected function createRunner() - { - return new PHPUnit_TextUI_TestRunner($this->arguments['loader']); - } - - /** - * Handles the command-line arguments. - * - * A child class of PHPUnit_TextUI_Command can hook into the argument - * parsing by adding the switch(es) to the $longOptions array and point to a - * callback method that handles the switch(es) in the child class like this - * - * - * longOptions['--my-switch'] = 'myHandler'; - * } - * - * // --my-switch foo -> myHandler('foo') - * protected function myHandler($value) - * { - * } - * } - * - * - * @param array $argv - */ - protected function handleArguments(array $argv) - { - try { - $this->options = PHPUnit_Util_Getopt::getopt( - $argv, - 'd:c:hv', - array_keys($this->longOptions) - ); - } - - catch (PHPUnit_Framework_Exception $e) { - PHPUnit_TextUI_TestRunner::showError($e->getMessage()); - } - - foreach ($this->options[0] as $option) { - switch ($option[0]) { - case '--colors': { - $this->arguments['colors'] = TRUE; - } - break; - - case '--bootstrap': { - $this->arguments['bootstrap'] = $option[1]; - } - break; - - case 'c': - case '--configuration': { - $this->arguments['configuration'] = $option[1]; - } - break; - - case '--coverage-clover': - case '--coverage-html': - case '--coverage-php': - case '--coverage-text': { - if (!extension_loaded('tokenizer')) { - $this->showExtensionNotLoadedMessage( - 'tokenizer', 'No code coverage will be generated.' - ); - - continue; - } - - if (!extension_loaded('xdebug')) { - $this->showExtensionNotLoadedMessage( - 'Xdebug', 'No code coverage will be generated.' - ); - - continue; - } - - switch ($option[0]) { - case '--coverage-clover': { - $this->arguments['coverageClover'] = $option[1]; - } - break; - - case '--coverage-html': { - $this->arguments['reportDirectory'] = $option[1]; - } - break; - - case '--coverage-php': { - $this->arguments['coveragePHP'] = $option[1]; - } - break; - - case '--coverage-text': { - if ($option[1] === NULL) { - $option[1] = 'php://stdout'; - } - - $this->arguments['coverageText'] = $option[1]; - $this->arguments['coverageTextShowUncoveredFiles'] = FALSE; - $this->arguments['coverageTextShowOnlySummary'] = FALSE; - } - break; - } - } - break; - - case 'd': { - $ini = explode('=', $option[1]); - - if (isset($ini[0])) { - if (isset($ini[1])) { - ini_set($ini[0], $ini[1]); - } else { - ini_set($ini[0], TRUE); - } - } - } - break; - - case '--debug': { - $this->arguments['debug'] = TRUE; - } - break; - - case 'h': - case '--help': { - $this->showHelp(); - exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); - } - break; - - case '--filter': { - $this->arguments['filter'] = $option[1]; - } - break; - - case '--testsuite': { - $this->arguments['testsuite'] = $option[1]; - } - break; - - case '--group': { - $this->arguments['groups'] = explode(',', $option[1]); - } - break; - - case '--exclude-group': { - $this->arguments['excludeGroups'] = explode( - ',', $option[1] - ); - } - break; - - case '--test-suffix': { - $this->arguments['testSuffixes'] = explode( - ',', $option[1] - ); - } - break; - - case '--include-path': { - $includePath = $option[1]; - } - break; - - case '--list-groups': { - $this->arguments['listGroups'] = TRUE; - } - break; - - case '--printer': { - $this->arguments['printer'] = $option[1]; - } - break; - - case '--loader': { - $this->arguments['loader'] = $option[1]; - } - break; - - case '--log-json': { - $this->arguments['jsonLogfile'] = $option[1]; - } - break; - - case '--log-junit': { - $this->arguments['junitLogfile'] = $option[1]; - } - break; - - case '--log-tap': { - $this->arguments['tapLogfile'] = $option[1]; - } - break; - - case '--process-isolation': { - $this->arguments['processIsolation'] = TRUE; - } - break; - - case '--repeat': { - $this->arguments['repeat'] = (int)$option[1]; - } - break; - - case '--stderr': { - $this->arguments['stderr'] = TRUE; - } - break; - - case '--stop-on-error': { - $this->arguments['stopOnError'] = TRUE; - } - break; - - case '--stop-on-failure': { - $this->arguments['stopOnFailure'] = TRUE; - } - break; - - case '--stop-on-incomplete': { - $this->arguments['stopOnIncomplete'] = TRUE; - } - break; - - case '--stop-on-skipped': { - $this->arguments['stopOnSkipped'] = TRUE; - } - break; - - case '--tap': { - $this->arguments['printer'] = new PHPUnit_Util_Log_TAP; - } - break; - - case '--testdox': { - $this->arguments['printer'] = new PHPUnit_Util_TestDox_ResultPrinter_Text; - } - break; - - case '--testdox-html': { - $this->arguments['testdoxHTMLFile'] = $option[1]; - } - break; - - case '--testdox-text': { - $this->arguments['testdoxTextFile'] = $option[1]; - } - break; - - case '--no-configuration': { - $this->arguments['useDefaultConfiguration'] = FALSE; - } - break; - - case '--no-globals-backup': { - $this->arguments['backupGlobals'] = FALSE; - } - break; - - case '--static-backup': { - $this->arguments['backupStaticAttributes'] = TRUE; - } - break; - - case 'v': - case '--verbose': { - $this->arguments['verbose'] = TRUE; - } - break; - - case '--version': { - PHPUnit_TextUI_TestRunner::printVersionString(); - exit(PHPUnit_TextUI_TestRunner::SUCCESS_EXIT); - } - break; - - case '--strict': { - $this->arguments['strict'] = TRUE; - } - break; - - default: { - $optionName = str_replace('--', '', $option[0]); - - if (isset($this->longOptions[$optionName])) { - $handler = $this->longOptions[$optionName]; - } - - else if (isset($this->longOptions[$optionName . '='])) { - $handler = $this->longOptions[$optionName . '=']; - } - - if (isset($handler) && is_callable(array($this, $handler))) { - $this->$handler($option[1]); - } - } - } - } - - $this->handleCustomTestSuite(); - - if (!isset($this->arguments['test'])) { - - if (isset($this->options[1][0])) { - $this->arguments['test'] = $this->options[1][0]; - } - - if (isset($this->options[1][1])) { - $this->arguments['testFile'] = realpath($this->options[1][1]); - } else { - $this->arguments['testFile'] = ''; - } - - if (isset($this->arguments['test']) && - is_file($this->arguments['test']) && - substr($this->arguments['test'], -5, 5) != '.phpt') { - $this->arguments['testFile'] = realpath($this->arguments['test']); - $this->arguments['test'] = substr($this->arguments['test'], 0, strrpos($this->arguments['test'], '.')); - } - } - - if (!isset($this->arguments['testSuffixes'])) { - $this->arguments['testSuffixes'] = array('Test.php', '.phpt'); - } - - if (isset($includePath)) { - ini_set( - 'include_path', - $includePath . PATH_SEPARATOR . ini_get('include_path') - ); - } - - if (isset($this->arguments['bootstrap'])) { - $this->handleBootstrap($this->arguments['bootstrap']); - } - - if (isset($this->arguments['printer']) && - is_string($this->arguments['printer'])) { - $this->arguments['printer'] = $this->handlePrinter($this->arguments['printer']); - } - - if ($this->arguments['loader'] !== NULL) { - $this->arguments['loader'] = $this->handleLoader($this->arguments['loader']); - } - - if (isset($this->arguments['configuration']) && - is_dir($this->arguments['configuration'])) { - $configurationFile = $this->arguments['configuration'] . - '/phpunit.xml'; - - if (file_exists($configurationFile)) { - $this->arguments['configuration'] = realpath( - $configurationFile - ); - } - - else if (file_exists($configurationFile . '.dist')) { - $this->arguments['configuration'] = realpath( - $configurationFile . '.dist' - ); - } - } - - else if (!isset($this->arguments['configuration']) && - $this->arguments['useDefaultConfiguration']) { - if (file_exists('phpunit.xml')) { - $this->arguments['configuration'] = realpath('phpunit.xml'); - } else if (file_exists('phpunit.xml.dist')) { - $this->arguments['configuration'] = realpath( - 'phpunit.xml.dist' - ); - } - } - - if (isset($this->arguments['configuration'])) { - try { - $configuration = PHPUnit_Util_Configuration::getInstance( - $this->arguments['configuration'] - ); - } - - catch (Exception $e) { - print $e->getMessage() . "\n"; - exit(PHPUnit_TextUI_TestRunner::FAILURE_EXIT); - } - - $phpunit = $configuration->getPHPUnitConfiguration(); - - $configuration->handlePHPConfiguration(); - - if (!isset($this->arguments['bootstrap']) && isset($phpunit['bootstrap'])) { - $this->handleBootstrap($phpunit['bootstrap']); - } - - if (isset($phpunit['printerClass'])) { - if (isset($phpunit['printerFile'])) { - $file = $phpunit['printerFile']; - } else { - $file = ''; - } - - $this->arguments['printer'] = $this->handlePrinter( - $phpunit['printerClass'], $file - ); - } - - if (isset($phpunit['testSuiteLoaderClass'])) { - if (isset($phpunit['testSuiteLoaderFile'])) { - $file = $phpunit['testSuiteLoaderFile']; - } else { - $file = ''; - } - - $this->arguments['loader'] = $this->handleLoader( - $phpunit['testSuiteLoaderClass'], $file - ); - } - - $logging = $configuration->getLoggingConfiguration(); - - if (isset($logging['coverage-html']) || isset($logging['coverage-clover']) || isset($logging['coverage-text']) ) { - if (!extension_loaded('tokenizer')) { - $this->showExtensionNotLoadedMessage( - 'tokenizer', 'No code coverage will be generated.' - ); - } - - else if (!extension_loaded('Xdebug')) { - $this->showExtensionNotLoadedMessage( - 'Xdebug', 'No code coverage will be generated.' - ); - } - } - - $browsers = $configuration->getSeleniumBrowserConfiguration(); - - if (!empty($browsers) && - class_exists('PHPUnit_Extensions_SeleniumTestCase')) { - PHPUnit_Extensions_SeleniumTestCase::$browsers = $browsers; - } - - if (!isset($this->arguments['test'])) { - $testSuite = $configuration->getTestSuiteConfiguration(isset($this->arguments['testsuite']) ? $this->arguments['testsuite'] : null); - - if ($testSuite !== NULL) { - $this->arguments['test'] = $testSuite; - } - } - } - - if (isset($this->arguments['test']) && is_string($this->arguments['test']) && substr($this->arguments['test'], -5, 5) == '.phpt') { - $test = new PHPUnit_Extensions_PhptTestCase($this->arguments['test']); - - $this->arguments['test'] = new PHPUnit_Framework_TestSuite; - $this->arguments['test']->addTest($test); - } - - if (!isset($this->arguments['test']) || - (isset($this->arguments['testDatabaseLogRevision']) && !isset($this->arguments['testDatabaseDSN']))) { - $this->showHelp(); - exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); - } - } - - /** - * Handles the loading of the PHPUnit_Runner_TestSuiteLoader implementation. - * - * @param string $loaderClass - * @param string $loaderFile - * @return PHPUnit_Runner_TestSuiteLoader - */ - protected function handleLoader($loaderClass, $loaderFile = '') - { - if (!class_exists($loaderClass, FALSE)) { - if ($loaderFile == '') { - $loaderFile = PHPUnit_Util_Filesystem::classNameToFilename( - $loaderClass - ); - } - - $loaderFile = stream_resolve_include_path($loaderFile); - - if ($loaderFile) { - require $loaderFile; - } - } - - if (class_exists($loaderClass, FALSE)) { - $class = new ReflectionClass($loaderClass); - - if ($class->implementsInterface('PHPUnit_Runner_TestSuiteLoader') && - $class->isInstantiable()) { - $loader = $class->newInstance(); - } - } - - if (!isset($loader)) { - PHPUnit_TextUI_TestRunner::showError( - sprintf( - 'Could not use "%s" as loader.', - - $loaderClass - ) - ); - } - - return $loader; - } - - /** - * Handles the loading of the PHPUnit_Util_Printer implementation. - * - * @param string $printerClass - * @param string $printerFile - * @return PHPUnit_Util_Printer - */ - protected function handlePrinter($printerClass, $printerFile = '') - { - if (!class_exists($printerClass, FALSE)) { - if ($printerFile == '') { - $printerFile = PHPUnit_Util_Filesystem::classNameToFilename( - $printerClass - ); - } - - $printerFile = stream_resolve_include_path($printerFile); - - if ($printerFile) { - require $printerFile; - } - } - - if (class_exists($printerClass, FALSE)) { - $class = new ReflectionClass($printerClass); - - if ($class->implementsInterface('PHPUnit_Framework_TestListener') && - $class->isSubclassOf('PHPUnit_Util_Printer') && - $class->isInstantiable()) { - if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) { - return $printerClass; - } - - $printer = $class->newInstance(); - } - } - - if (!isset($printer)) { - PHPUnit_TextUI_TestRunner::showError( - sprintf( - 'Could not use "%s" as printer.', - - $printerClass - ) - ); - } - - return $printer; - } - - /** - * Loads a bootstrap file. - * - * @param string $filename - */ - protected function handleBootstrap($filename) - { - try { - PHPUnit_Util_Fileloader::checkAndLoad($filename); - } - - catch (PHPUnit_Framework_Exception $e) { - PHPUnit_TextUI_TestRunner::showError($e->getMessage()); - } - } - - /** - * @param string $message - * @since Method available since Release 3.6.0 - */ - protected function showExtensionNotLoadedMessage($extension, $message = '') - { - if (isset($this->missingExtensions[$extension])) { - return; - } - - if (!empty($message)) { - $message = ' ' . $message; - } - - $this->showMessage( - 'The ' . $extension . ' extension is not loaded.' . $message . "\n", - FALSE - ); - - $this->missingExtensions[$extension] = TRUE; - } - - /** - * Shows a message. - * - * @param string $message - * @param boolean $exit - */ - protected function showMessage($message, $exit = TRUE) - { - PHPUnit_TextUI_TestRunner::printVersionString(); - print $message . "\n"; - - if ($exit) { - exit(PHPUnit_TextUI_TestRunner::EXCEPTION_EXIT); - } else { - print "\n"; - } - } - - /** - * Show the help message. - */ - protected function showHelp() - { - PHPUnit_TextUI_TestRunner::printVersionString(); - - print << - - --log-junit Log test execution in JUnit XML format to file. - --log-tap Log test execution in TAP format to file. - --log-json Log test execution in JSON format. - - --coverage-clover Generate code coverage report in Clover XML format. - --coverage-html Generate code coverage report in HTML format. - --coverage-php Serialize PHP_CodeCoverage object to file. - --coverage-text= Generate code coverage report in text format. - Default to writing to the standard output. - - --testdox-html Write agile documentation in HTML format to file. - --testdox-text Write agile documentation in Text format to file. - - --filter Filter which tests to run. - --testsuite Filter which testsuite to run. - --group ... Only runs tests from the specified group(s). - --exclude-group ... Exclude tests from the specified group(s). - --list-groups List available test groups. - --test-suffix ... Only search for test in files with specified - suffix(es). Default: Test.php,.phpt - - --loader TestSuiteLoader implementation to use. - --printer TestSuiteListener implementation to use. - --repeat Runs the test(s) repeatedly. - - --tap Report test execution progress in TAP format. - --testdox Report test execution progress in TestDox format. - - --colors Use colors in output. - --stderr Write to STDERR instead of STDOUT. - --stop-on-error Stop execution upon first error. - --stop-on-failure Stop execution upon first error or failure. - --stop-on-skipped Stop execution upon first skipped test. - --stop-on-incomplete Stop execution upon first incomplete test. - --strict Run tests in strict mode. - -v|--verbose Output more verbose information. - --debug Display debugging information during test execution. - - --process-isolation Run each test in a separate PHP process. - --no-globals-backup Do not backup and restore \$GLOBALS for each test. - --static-backup Backup and restore static attributes for each test. - - --bootstrap A "bootstrap" PHP file that is run before the tests. - -c|--configuration Read configuration from XML file. - --no-configuration Ignore default configuration file (phpunit.xml). - --include-path Prepend PHP's include_path with given path(s). - -d key[=value] Sets a php.ini value. - - -h|--help Prints this usage information. - --version Prints the version and exits. - -EOT; - } - - /** - * Custom callback for test suite discovery. - */ - protected function handleCustomTestSuite() - { - } -} diff --git a/PHPUnit/TextUI/ResultPrinter.php b/PHPUnit/TextUI/ResultPrinter.php deleted file mode 100644 index d5a1a459e00..00000000000 --- a/PHPUnit/TextUI/ResultPrinter.php +++ /dev/null @@ -1,666 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Prints the result of a TextUI TestRunner run. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_TextUI_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener -{ - const EVENT_TEST_START = 0; - const EVENT_TEST_END = 1; - const EVENT_TESTSUITE_START = 2; - const EVENT_TESTSUITE_END = 3; - - /** - * @var integer - */ - protected $column = 0; - - /** - * @var integer - */ - protected $maxColumn; - - /** - * @var boolean - */ - protected $lastTestFailed = FALSE; - - /** - * @var integer - */ - protected $numAssertions = 0; - - /** - * @var integer - */ - protected $numTests = -1; - - /** - * @var integer - */ - protected $numTestsRun = 0; - - /** - * @var integer - */ - protected $numTestsWidth; - - /** - * @var boolean - */ - protected $colors = FALSE; - - /** - * @var boolean - */ - protected $debug = FALSE; - - /** - * @var boolean - */ - protected $verbose = FALSE; - - /** - * Constructor. - * - * @param mixed $out - * @param boolean $verbose - * @param boolean $colors - * @param boolean $debug - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.0.0 - */ - public function __construct($out = NULL, $verbose = FALSE, $colors = FALSE, $debug = FALSE) - { - parent::__construct($out); - - if (is_bool($verbose)) { - $this->verbose = $verbose; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(2, 'boolean'); - } - - if (is_bool($colors)) { - $this->colors = $colors; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(3, 'boolean'); - } - - if (is_bool($debug)) { - $this->debug = $debug; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(4, 'boolean'); - } - } - - /** - * @param PHPUnit_Framework_TestResult $result - */ - public function printResult(PHPUnit_Framework_TestResult $result) - { - $this->printHeader(); - - if ($result->errorCount() > 0) { - $this->printErrors($result); - } - - if ($result->failureCount() > 0) { - if ($result->errorCount() > 0) { - print "\n--\n\n"; - } - - $this->printFailures($result); - } - - if ($this->verbose) { - if ($result->deprecatedFeaturesCount() > 0) { - if ($result->failureCount() > 0) { - print "\n--\n\nDeprecated PHPUnit features are being used"; - } - - foreach ($result->deprecatedFeatures() as $deprecatedFeature) { - $this->write($deprecatedFeature . "\n\n"); - } - } - - if ($result->notImplementedCount() > 0) { - if ($result->failureCount() > 0) { - print "\n--\n\n"; - } - - $this->printIncompletes($result); - } - - if ($result->skippedCount() > 0) { - if ($result->notImplementedCount() > 0) { - print "\n--\n\n"; - } - - $this->printSkipped($result); - } - } - - $this->printFooter($result); - } - - /** - * @param array $defects - * @param integer $count - * @param string $type - */ - protected function printDefects(array $defects, $count, $type) - { - static $called = FALSE; - - if ($count == 0) { - return; - } - - $this->write( - sprintf( - "%sThere %s %d %s%s:\n", - - $called ? "\n" : '', - ($count == 1) ? 'was' : 'were', - $count, - $type, - ($count == 1) ? '' : 's' - ) - ); - - $i = 1; - - foreach ($defects as $defect) { - $this->printDefect($defect, $i++); - } - - $called = TRUE; - } - - /** - * @param PHPUnit_Framework_TestFailure $defect - * @param integer $count - */ - protected function printDefect(PHPUnit_Framework_TestFailure $defect, $count) - { - $this->printDefectHeader($defect, $count); - $this->printDefectTrace($defect); - } - - /** - * @param PHPUnit_Framework_TestFailure $defect - * @param integer $count - */ - protected function printDefectHeader(PHPUnit_Framework_TestFailure $defect, $count) - { - $failedTest = $defect->failedTest(); - - if ($failedTest instanceof PHPUnit_Framework_SelfDescribing) { - $testName = $failedTest->toString(); - } else { - $testName = get_class($failedTest); - } - - $this->write( - sprintf( - "\n%d) %s\n", - - $count, - $testName - ) - ); - } - - /** - * @param PHPUnit_Framework_TestFailure $defect - */ - protected function printDefectTrace(PHPUnit_Framework_TestFailure $defect) - { - $this->write( - $defect->getExceptionAsString() . "\n" . - PHPUnit_Util_Filter::getFilteredStacktrace( - $defect->thrownException() - ) - ); - - $e = $defect->thrownException()->getPrevious(); - - while ($e) { - $this->write( - "\nCaused by\n" . - PHPUnit_Framework_TestFailure::exceptionToString($e). "\n" . - PHPUnit_Util_Filter::getFilteredStacktrace($e) - ); - - $e = $e->getPrevious(); - } - } - - /** - * @param PHPUnit_Framework_TestResult $result - */ - protected function printErrors(PHPUnit_Framework_TestResult $result) - { - $this->printDefects($result->errors(), $result->errorCount(), 'error'); - } - - /** - * @param PHPUnit_Framework_TestResult $result - */ - protected function printFailures(PHPUnit_Framework_TestResult $result) - { - $this->printDefects( - $result->failures(), - $result->failureCount(), - 'failure' - ); - } - - /** - * @param PHPUnit_Framework_TestResult $result - */ - protected function printIncompletes(PHPUnit_Framework_TestResult $result) - { - $this->printDefects( - $result->notImplemented(), - $result->notImplementedCount(), - 'incomplete test' - ); - } - - /** - * @param PHPUnit_Framework_TestResult $result - * @since Method available since Release 3.0.0 - */ - protected function printSkipped(PHPUnit_Framework_TestResult $result) - { - $this->printDefects( - $result->skipped(), - $result->skippedCount(), - 'skipped test' - ); - } - - protected function printHeader() - { - $timer = new PHP_Timer; - - $this->write("\n\n" . $timer->resourceUsage() . "\n\n"); - } - - /** - * @param PHPUnit_Framework_TestResult $result - */ - protected function printFooter(PHPUnit_Framework_TestResult $result) - { - if (count($result) === 0) { - if ($this->colors) { - $this->write("\x1b[30;43m\x1b[2K"); - } - - $this->write( - "No tests executed!\n" - ); - - if ($this->colors) { - $this->write("\x1b[0m\x1b[2K"); - } - } - - else if ($result->wasSuccessful() && - $result->allCompletelyImplemented() && - $result->noneSkipped()) { - if ($this->colors) { - $this->write("\x1b[30;42m\x1b[2K"); - } - - $this->write( - sprintf( - "OK (%d test%s, %d assertion%s)\n", - - count($result), - (count($result) == 1) ? '' : 's', - $this->numAssertions, - ($this->numAssertions == 1) ? '' : 's' - ) - ); - - if ($this->colors) { - $this->write("\x1b[0m\x1b[2K"); - } - } - - else if ((!$result->allCompletelyImplemented() || - !$result->noneSkipped()) && - $result->wasSuccessful()) { - if ($this->colors) { - $this->write( - "\x1b[30;43m\x1b[2KOK, but incomplete or skipped tests!\n" . - "\x1b[0m\x1b[30;43m\x1b[2K" - ); - } else { - $this->write("OK, but incomplete or skipped tests!\n"); - } - - $this->write( - sprintf( - "Tests: %d, Assertions: %d%s%s.\n", - - count($result), - $this->numAssertions, - $this->getCountString( - $result->notImplementedCount(), 'Incomplete' - ), - $this->getCountString( - $result->skippedCount(), 'Skipped' - ) - ) - ); - - if ($this->colors) { - $this->write("\x1b[0m\x1b[2K"); - } - } - - else { - $this->write("\n"); - - if ($this->colors) { - $this->write( - "\x1b[37;41m\x1b[2KFAILURES!\n\x1b[0m\x1b[37;41m\x1b[2K" - ); - } else { - $this->write("FAILURES!\n"); - } - - $this->write( - sprintf( - "Tests: %d, Assertions: %s%s%s%s%s.\n", - - count($result), - $this->numAssertions, - $this->getCountString($result->failureCount(), 'Failures'), - $this->getCountString($result->errorCount(), 'Errors'), - $this->getCountString( - $result->notImplementedCount(), 'Incomplete' - ), - $this->getCountString($result->skippedCount(), 'Skipped') - ) - ); - - if ($this->colors) { - $this->write("\x1b[0m\x1b[2K"); - } - } - - if (!$this->verbose && - $result->deprecatedFeaturesCount() > 0) { - $message = sprintf( - "Warning: Deprecated PHPUnit features are being used %s times!\n" . - "Use --verbose for more information.\n", - $result->deprecatedFeaturesCount() - ); - - if ($this->colors) { - $message = "\x1b[37;41m\x1b[2K" . $message . - "\x1b[0m"; - } - - $this->write("\n" . $message); - } - } - - /** - * @param integer $count - * @param string $name - * @return string - * @since Method available since Release 3.0.0 - */ - protected function getCountString($count, $name) - { - $string = ''; - - if ($count > 0) { - $string = sprintf( - ', %s: %d', - - $name, - $count - ); - } - - return $string; - } - - /** - */ - public function printWaitPrompt() - { - $this->write("\n to continue\n"); - } - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->colors) { - $this->writeProgress("\x1b[31;1mE\x1b[0m"); - } else { - $this->writeProgress('E'); - } - - $this->lastTestFailed = TRUE; - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - if ($this->colors) { - $this->writeProgress("\x1b[41;37mF\x1b[0m"); - } else { - $this->writeProgress('F'); - } - - $this->lastTestFailed = TRUE; - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->colors) { - $this->writeProgress("\x1b[33;1mI\x1b[0m"); - } else { - $this->writeProgress('I'); - } - - $this->lastTestFailed = TRUE; - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->colors) { - $this->writeProgress("\x1b[36;1mS\x1b[0m"); - } else { - $this->writeProgress('S'); - } - - $this->lastTestFailed = TRUE; - } - - /** - * A testsuite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - if ($this->numTests == -1) { - $this->numTests = count($suite); - $this->numTestsWidth = strlen((string)$this->numTests); - $this->maxColumn = 69 - (2 * $this->numTestsWidth); - } - } - - /** - * A testsuite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - if ($this->debug) { - $this->write( - sprintf( - "\nStarting test '%s'.\n", PHPUnit_Util_Test::describe($test) - ) - ); - } - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if (!$this->lastTestFailed) { - $this->writeProgress('.'); - } - - if ($test instanceof PHPUnit_Framework_TestCase) { - $this->numAssertions += $test->getNumAssertions(); - } - - else if ($test instanceof PHPUnit_Extensions_PhptTestCase) { - $this->numAssertions++; - } - - $this->lastTestFailed = FALSE; - - if ($test instanceof PHPUnit_Framework_TestCase) { - if (!$test->hasPerformedExpectationsOnOutput()) { - $this->write($test->getActualOutput()); - } - } - } - - /** - * @param string $progress - */ - protected function writeProgress($progress) - { - $this->write($progress); - $this->column++; - $this->numTestsRun++; - - if ($this->column == $this->maxColumn) { - $this->write( - sprintf( - ' %' . $this->numTestsWidth . 'd / %' . - $this->numTestsWidth . 'd (%3s%%)', - - $this->numTestsRun, - $this->numTests, - floor(($this->numTestsRun / $this->numTests) * 100) - ) - ); - - $this->writeNewLine(); - } - } - - protected function writeNewLine() - { - $this->column = 0; - $this->write("\n"); - } -} diff --git a/PHPUnit/TextUI/TestRunner.php b/PHPUnit/TextUI/TestRunner.php deleted file mode 100644 index 3d7632ad204..00000000000 --- a/PHPUnit/TextUI/TestRunner.php +++ /dev/null @@ -1,867 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * A TestRunner for the Command Line Interface (CLI) - * PHP SAPI Module. - * - * @package PHPUnit - * @subpackage TextUI - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_TextUI_TestRunner extends PHPUnit_Runner_BaseTestRunner -{ - const SUCCESS_EXIT = 0; - const FAILURE_EXIT = 1; - const EXCEPTION_EXIT = 2; - - /** - * @var PHP_CodeCoverage_Filter - */ - protected $codeCoverageFilter; - - /** - * @var PHPUnit_Runner_TestSuiteLoader - */ - protected $loader = NULL; - - /** - * @var PHPUnit_TextUI_ResultPrinter - */ - protected $printer = NULL; - - /** - * @var boolean - */ - protected static $versionStringPrinted = FALSE; - - /** - * @param PHPUnit_Runner_TestSuiteLoader $loader - * @param PHP_CodeCoverage_Filter $filter - * @since Method available since Release 3.4.0 - */ - public function __construct(PHPUnit_Runner_TestSuiteLoader $loader = NULL, PHP_CodeCoverage_Filter $filter = NULL) - { - if ($filter === NULL) { - $filter = new PHP_CodeCoverage_Filter; - } - - $this->codeCoverageFilter = $filter; - $this->loader = $loader; - } - - /** - * @param mixed $test - * @param array $arguments - * @throws PHPUnit_Framework_Exception - */ - public static function run($test, array $arguments = array()) - { - if ($test instanceof ReflectionClass) { - $test = new PHPUnit_Framework_TestSuite($test); - } - - if ($test instanceof PHPUnit_Framework_Test) { - $aTestRunner = new PHPUnit_TextUI_TestRunner; - - return $aTestRunner->doRun( - $test, - $arguments - ); - } else { - throw new PHPUnit_Framework_Exception( - 'No test case or test suite found.' - ); - } - } - - /** - * @return PHPUnit_Framework_TestResult - */ - protected function createTestResult() - { - return new PHPUnit_Framework_TestResult; - } - - private function processSuiteFilters(PHPUnit_Framework_TestSuite $suite, array $arguments) { - if (!$arguments['filter'] && - empty($arguments['groups']) && - empty($arguments['excludeGroups'])) { - return; - } - - $filterFactory = new PHPUnit_Runner_Filter_Factory(); - - if(!empty($arguments['excludeGroups'])) { - $filterFactory->addFilter( - new ReflectionClass('PHPUnit_Runner_Filter_Group_Exclude'), - $arguments['excludeGroups'] - ); - } - - if(!empty($arguments['groups'])) { - $filterFactory->addFilter( - new ReflectionClass('PHPUnit_Runner_Filter_Group_Include'), - $arguments['groups'] - ); - } - - if($arguments['filter']) { - $filterFactory->addFilter( - new ReflectionClass('PHPUnit_Runner_Filter_Test'), - $arguments['filter'] - ); - } - $suite->injectFilter($filterFactory); - } - - /** - * @param PHPUnit_Framework_Test $suite - * @param array $arguments - * @return PHPUnit_Framework_TestResult - */ - public function doRun(PHPUnit_Framework_Test $suite, array $arguments = array()) - { - $this->handleConfiguration($arguments); - - $this->processSuiteFilters($suite, $arguments); - - if (isset($arguments['bootstrap'])) { - $GLOBALS['__PHPUNIT_BOOTSTRAP'] = $arguments['bootstrap']; - } - - if ($arguments['backupGlobals'] === FALSE) { - $suite->setBackupGlobals(FALSE); - } - - if ($arguments['backupStaticAttributes'] === TRUE) { - $suite->setBackupStaticAttributes(TRUE); - } - - if (is_integer($arguments['repeat'])) { - $test = new PHPUnit_Extensions_RepeatedTest( - $suite, - $arguments['repeat'], - $arguments['processIsolation'] - ); - - $suite = new PHPUnit_Framework_TestSuite(); - $suite->addTest($test); - } - - $result = $this->createTestResult(); - - if (!$arguments['convertErrorsToExceptions']) { - $result->convertErrorsToExceptions(FALSE); - } - - if (!$arguments['convertNoticesToExceptions']) { - PHPUnit_Framework_Error_Notice::$enabled = FALSE; - } - - if (!$arguments['convertWarningsToExceptions']) { - PHPUnit_Framework_Error_Warning::$enabled = FALSE; - } - - if ($arguments['stopOnError']) { - $result->stopOnError(TRUE); - } - - if ($arguments['stopOnFailure']) { - $result->stopOnFailure(TRUE); - } - - if ($arguments['stopOnIncomplete']) { - $result->stopOnIncomplete(TRUE); - } - - if ($arguments['stopOnSkipped']) { - $result->stopOnSkipped(TRUE); - } - - if ($this->printer === NULL) { - if (isset($arguments['printer']) && - $arguments['printer'] instanceof PHPUnit_Util_Printer) { - $this->printer = $arguments['printer']; - } else { - $printerClass = 'PHPUnit_TextUI_ResultPrinter'; - if (isset($arguments['printer']) && - is_string($arguments['printer']) && - class_exists($arguments['printer'], FALSE)) { - $class = new ReflectionClass($arguments['printer']); - - if ($class->isSubclassOf('PHPUnit_TextUI_ResultPrinter')) { - $printerClass = $arguments['printer']; - } - } - - $this->printer = new $printerClass( - isset($arguments['stderr']) ? 'php://stderr' : NULL, - $arguments['verbose'], - $arguments['colors'], - $arguments['debug'] - ); - } - } - - if (!$this->printer instanceof PHPUnit_Util_Log_TAP && - !self::$versionStringPrinted) { - $this->printer->write( - PHPUnit_Runner_Version::getVersionString() . "\n\n" - ); - - if (isset($arguments['configuration'])) { - $this->printer->write( - sprintf( - "Configuration read from %s\n\n", - $arguments['configuration']->getFilename() - ) - ); - } - } - - foreach ($arguments['listeners'] as $listener) { - $result->addListener($listener); - } - - $result->addListener($this->printer); - - if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) { - $result->addListener(new PHPUnit_Util_DeprecatedFeature_Logger); - } - - if (isset($arguments['testdoxHTMLFile'])) { - $result->addListener( - new PHPUnit_Util_TestDox_ResultPrinter_HTML( - $arguments['testdoxHTMLFile'] - ) - ); - } - - if (isset($arguments['testdoxTextFile'])) { - $result->addListener( - new PHPUnit_Util_TestDox_ResultPrinter_Text( - $arguments['testdoxTextFile'] - ) - ); - } - - $codeCoverageReports = 0; - - if (extension_loaded('xdebug')) { - if (isset($arguments['coverageClover'])) { - $codeCoverageReports++; - } - - if (isset($arguments['reportDirectory'])) { - $codeCoverageReports++; - } - - if (isset($arguments['coveragePHP'])) { - $codeCoverageReports++; - } - - if (isset($arguments['coverageText'])) { - $codeCoverageReports++; - } - } - - if ($codeCoverageReports > 0) { - $codeCoverage = new PHP_CodeCoverage( - NULL, $this->codeCoverageFilter - ); - - $codeCoverage->setAddUncoveredFilesFromWhitelist( - $arguments['addUncoveredFilesFromWhitelist'] - ); - - $codeCoverage->setCheckForUnintentionallyCoveredCode( - $arguments['strict'] - ); - - $codeCoverage->setProcessUncoveredFilesFromWhitelist( - $arguments['processUncoveredFilesFromWhitelist'] - ); - - if (isset($arguments['forceCoversAnnotation'])) { - $codeCoverage->setForceCoversAnnotation( - $arguments['forceCoversAnnotation'] - ); - } - - if (isset($arguments['mapTestClassNameToCoveredClassName'])) { - $codeCoverage->setMapTestClassNameToCoveredClassName( - $arguments['mapTestClassNameToCoveredClassName'] - ); - } - - $result->setCodeCoverage($codeCoverage); - } - - if ($codeCoverageReports > 1) { - if (isset($arguments['cacheTokens'])) { - $codeCoverage->setCacheTokens($arguments['cacheTokens']); - } - } - - if (isset($arguments['jsonLogfile'])) { - $result->addListener( - new PHPUnit_Util_Log_JSON($arguments['jsonLogfile']) - ); - } - - if (isset($arguments['tapLogfile'])) { - $result->addListener( - new PHPUnit_Util_Log_TAP($arguments['tapLogfile']) - ); - } - - if (isset($arguments['junitLogfile'])) { - $result->addListener( - new PHPUnit_Util_Log_JUnit( - $arguments['junitLogfile'], $arguments['logIncompleteSkipped'] - ) - ); - } - - if ($arguments['strict']) { - $result->strictMode(TRUE); - - $result->setTimeoutForSmallTests( - $arguments['timeoutForSmallTests'] - ); - - $result->setTimeoutForMediumTests( - $arguments['timeoutForMediumTests'] - ); - - $result->setTimeoutForLargeTests( - $arguments['timeoutForLargeTests'] - ); - } - - if ($suite instanceof PHPUnit_Framework_TestSuite) { - $suite->setRunTestInSeparateProcess($arguments['processIsolation']); - } - - $suite->run($result); - - unset($suite); - $result->flushListeners(); - - if ($this->printer instanceof PHPUnit_TextUI_ResultPrinter) { - $this->printer->printResult($result); - } - - if (isset($codeCoverage)) { - if (isset($arguments['coverageClover'])) { - $this->printer->write( - "\nGenerating code coverage report in Clover XML format ..." - ); - - $writer = new PHP_CodeCoverage_Report_Clover; - $writer->process($codeCoverage, $arguments['coverageClover']); - - $this->printer->write(" done\n"); - unset($writer); - } - - if (isset($arguments['reportDirectory'])) { - $this->printer->write( - "\nGenerating code coverage report in HTML format ..." - ); - - $writer = new PHP_CodeCoverage_Report_HTML( - $arguments['reportCharset'], - $arguments['reportHighlight'], - $arguments['reportLowUpperBound'], - $arguments['reportHighLowerBound'], - sprintf( - ' and PHPUnit %s', - PHPUnit_Runner_Version::id() - ) - ); - - $writer->process($codeCoverage, $arguments['reportDirectory']); - - $this->printer->write(" done\n"); - unset($writer); - } - - if (isset($arguments['coveragePHP'])) { - $this->printer->write( - "\nGenerating code coverage report in PHP format ..." - ); - - $writer = new PHP_CodeCoverage_Report_PHP; - $writer->process($codeCoverage, $arguments['coveragePHP']); - - $this->printer->write(" done\n"); - unset($writer); - } - - if (isset($arguments['coverageText'])) { - if ($arguments['coverageText'] == 'php://stdout') { - $outputStream = $this->printer; - $colors = (bool)$arguments['colors']; - } else { - $outputStream = new PHPUnit_Util_Printer($arguments['coverageText']); - $colors = FALSE; - } - - $writer = new PHP_CodeCoverage_Report_Text( - $outputStream, - $arguments['reportLowUpperBound'], - $arguments['reportHighLowerBound'], - $arguments['coverageTextShowUncoveredFiles'], - $arguments['coverageTextShowOnlySummary'] - ); - - $writer->process($codeCoverage, $colors); - } - } - - return $result; - } - - /** - * @param PHPUnit_TextUI_ResultPrinter $resultPrinter - */ - public function setPrinter(PHPUnit_TextUI_ResultPrinter $resultPrinter) - { - $this->printer = $resultPrinter; - } - - /** - * Override to define how to handle a failed loading of - * a test suite. - * - * @param string $message - */ - protected function runFailed($message) - { - self::printVersionString(); - self::write($message . PHP_EOL); - exit(self::FAILURE_EXIT); - } - - /** - * @param string $buffer - * @since Method available since Release 3.1.0 - */ - protected static function write($buffer) - { - if (PHP_SAPI != 'cli') { - $buffer = htmlspecialchars($buffer); - } - - print $buffer; - } - - /** - * Returns the loader to be used. - * - * @return PHPUnit_Runner_TestSuiteLoader - * @since Method available since Release 2.2.0 - */ - public function getLoader() - { - if ($this->loader === NULL) { - $this->loader = new PHPUnit_Runner_StandardTestSuiteLoader; - } - - return $this->loader; - } - - /** - */ - public static function showError($message) - { - self::printVersionString(); - self::write($message . "\n"); - - exit(self::FAILURE_EXIT); - } - - /** - */ - public static function printVersionString() - { - if (!self::$versionStringPrinted) { - self::write(PHPUnit_Runner_Version::getVersionString() . "\n\n"); - self::$versionStringPrinted = TRUE; - } - } - - /** - * @param array $arguments - * @since Method available since Release 3.2.1 - */ - protected function handleConfiguration(array &$arguments) - { - if (isset($arguments['configuration']) && - !$arguments['configuration'] instanceof PHPUnit_Util_Configuration) { - $arguments['configuration'] = PHPUnit_Util_Configuration::getInstance( - $arguments['configuration'] - ); - } - - $arguments['debug'] = isset($arguments['debug']) ? $arguments['debug'] : FALSE; - $arguments['filter'] = isset($arguments['filter']) ? $arguments['filter'] : FALSE; - $arguments['listeners'] = isset($arguments['listeners']) ? $arguments['listeners'] : array(); - - if (isset($arguments['configuration'])) { - $arguments['configuration']->handlePHPConfiguration(); - - $phpunitConfiguration = $arguments['configuration']->getPHPUnitConfiguration(); - - if (isset($phpunitConfiguration['backupGlobals']) && - !isset($arguments['backupGlobals'])) { - $arguments['backupGlobals'] = $phpunitConfiguration['backupGlobals']; - } - - if (isset($phpunitConfiguration['backupStaticAttributes']) && - !isset($arguments['backupStaticAttributes'])) { - $arguments['backupStaticAttributes'] = $phpunitConfiguration['backupStaticAttributes']; - } - - if (isset($phpunitConfiguration['bootstrap']) && - !isset($arguments['bootstrap'])) { - $arguments['bootstrap'] = $phpunitConfiguration['bootstrap']; - } - - if (isset($phpunitConfiguration['cacheTokens']) && - !isset($arguments['cacheTokens'])) { - $arguments['cacheTokens'] = $phpunitConfiguration['cacheTokens']; - } - - if (isset($phpunitConfiguration['colors']) && - !isset($arguments['colors'])) { - $arguments['colors'] = $phpunitConfiguration['colors']; - } - - if (isset($phpunitConfiguration['convertErrorsToExceptions']) && - !isset($arguments['convertErrorsToExceptions'])) { - $arguments['convertErrorsToExceptions'] = $phpunitConfiguration['convertErrorsToExceptions']; - } - - if (isset($phpunitConfiguration['convertNoticesToExceptions']) && - !isset($arguments['convertNoticesToExceptions'])) { - $arguments['convertNoticesToExceptions'] = $phpunitConfiguration['convertNoticesToExceptions']; - } - - if (isset($phpunitConfiguration['convertWarningsToExceptions']) && - !isset($arguments['convertWarningsToExceptions'])) { - $arguments['convertWarningsToExceptions'] = $phpunitConfiguration['convertWarningsToExceptions']; - } - - if (isset($phpunitConfiguration['processIsolation']) && - !isset($arguments['processIsolation'])) { - $arguments['processIsolation'] = $phpunitConfiguration['processIsolation']; - } - - if (isset($phpunitConfiguration['stopOnFailure']) && - !isset($arguments['stopOnFailure'])) { - $arguments['stopOnFailure'] = $phpunitConfiguration['stopOnFailure']; - } - - if (isset($phpunitConfiguration['timeoutForSmallTests']) && - !isset($arguments['timeoutForSmallTests'])) { - $arguments['timeoutForSmallTests'] = $phpunitConfiguration['timeoutForSmallTests']; - } - - if (isset($phpunitConfiguration['timeoutForMediumTests']) && - !isset($arguments['timeoutForMediumTests'])) { - $arguments['timeoutForMediumTests'] = $phpunitConfiguration['timeoutForMediumTests']; - } - - if (isset($phpunitConfiguration['timeoutForLargeTests']) && - !isset($arguments['timeoutForLargeTests'])) { - $arguments['timeoutForLargeTests'] = $phpunitConfiguration['timeoutForLargeTests']; - } - - if (isset($phpunitConfiguration['strict']) && - !isset($arguments['strict'])) { - $arguments['strict'] = $phpunitConfiguration['strict']; - } - - if (isset($phpunitConfiguration['verbose']) && - !isset($arguments['verbose'])) { - $arguments['verbose'] = $phpunitConfiguration['verbose']; - } - - if (isset($phpunitConfiguration['forceCoversAnnotation']) && - !isset($arguments['forceCoversAnnotation'])) { - $arguments['forceCoversAnnotation'] = $phpunitConfiguration['forceCoversAnnotation']; - } - - if (isset($phpunitConfiguration['mapTestClassNameToCoveredClassName']) && - !isset($arguments['mapTestClassNameToCoveredClassName'])) { - $arguments['mapTestClassNameToCoveredClassName'] = $phpunitConfiguration['mapTestClassNameToCoveredClassName']; - } - - $groupCliArgs = array(); - if (!empty($arguments['groups'])) { - $groupCliArgs = $arguments['groups']; - } - - $groupConfiguration = $arguments['configuration']->getGroupConfiguration(); - - if (!empty($groupConfiguration['include']) && - !isset($arguments['groups'])) { - $arguments['groups'] = $groupConfiguration['include']; - } - - if (!empty($groupConfiguration['exclude']) && - !isset($arguments['excludeGroups'])) { - $arguments['excludeGroups'] = array_diff($groupConfiguration['exclude'], $groupCliArgs); - } - - foreach ($arguments['configuration']->getListenerConfiguration() as $listener) { - if (!class_exists($listener['class'], FALSE) && - $listener['file'] !== '') { - require_once $listener['file']; - } - - if (class_exists($listener['class'])) { - if (count($listener['arguments']) == 0) { - $listener = new $listener['class']; - } else { - $listenerClass = new ReflectionClass( - $listener['class'] - ); - $listener = $listenerClass->newInstanceArgs( - $listener['arguments'] - ); - } - - if ($listener instanceof PHPUnit_Framework_TestListener) { - $arguments['listeners'][] = $listener; - } - } - } - - $loggingConfiguration = $arguments['configuration']->getLoggingConfiguration(); - - if (isset($loggingConfiguration['coverage-html']) && - !isset($arguments['reportDirectory'])) { - if (isset($loggingConfiguration['charset']) && - !isset($arguments['reportCharset'])) { - $arguments['reportCharset'] = $loggingConfiguration['charset']; - } - - if (isset($loggingConfiguration['highlight']) && - !isset($arguments['reportHighlight'])) { - $arguments['reportHighlight'] = $loggingConfiguration['highlight']; - } - - if (isset($loggingConfiguration['lowUpperBound']) && - !isset($arguments['reportLowUpperBound'])) { - $arguments['reportLowUpperBound'] = $loggingConfiguration['lowUpperBound']; - } - - if (isset($loggingConfiguration['highLowerBound']) && - !isset($arguments['reportHighLowerBound'])) { - $arguments['reportHighLowerBound'] = $loggingConfiguration['highLowerBound']; - } - - $arguments['reportDirectory'] = $loggingConfiguration['coverage-html']; - } - - if (isset($loggingConfiguration['coverage-clover']) && - !isset($arguments['coverageClover'])) { - $arguments['coverageClover'] = $loggingConfiguration['coverage-clover']; - } - - if (isset($loggingConfiguration['coverage-php']) && - !isset($arguments['coveragePHP'])) { - $arguments['coveragePHP'] = $loggingConfiguration['coverage-php']; - } - - if (isset($loggingConfiguration['coverage-text']) && - !isset($arguments['coverageText'])) { - $arguments['coverageText'] = $loggingConfiguration['coverage-text']; - if (isset($loggingConfiguration['coverageTextShowUncoveredFiles'])) { - $arguments['coverageTextShowUncoveredFiles'] = $loggingConfiguration['coverageTextShowUncoveredFiles']; - } else { - $arguments['coverageTextShowUncoveredFiles'] = FALSE; - } - if (isset($loggingConfiguration['coverageTextShowOnlySummary'])) { - $arguments['coverageTextShowOnlySummary'] = $loggingConfiguration['coverageTextShowOnlySummary']; - } else { - $arguments['coverageTextShowOnlySummary'] = FALSE; - } - } - - if (isset($loggingConfiguration['json']) && - !isset($arguments['jsonLogfile'])) { - $arguments['jsonLogfile'] = $loggingConfiguration['json']; - } - - if (isset($loggingConfiguration['plain'])) { - $arguments['listeners'][] = new PHPUnit_TextUI_ResultPrinter( - $loggingConfiguration['plain'], TRUE - ); - } - - if (isset($loggingConfiguration['tap']) && - !isset($arguments['tapLogfile'])) { - $arguments['tapLogfile'] = $loggingConfiguration['tap']; - } - - if (isset($loggingConfiguration['junit']) && - !isset($arguments['junitLogfile'])) { - $arguments['junitLogfile'] = $loggingConfiguration['junit']; - - if (isset($loggingConfiguration['logIncompleteSkipped']) && - !isset($arguments['logIncompleteSkipped'])) { - $arguments['logIncompleteSkipped'] = $loggingConfiguration['logIncompleteSkipped']; - } - } - - if (isset($loggingConfiguration['testdox-html']) && - !isset($arguments['testdoxHTMLFile'])) { - $arguments['testdoxHTMLFile'] = $loggingConfiguration['testdox-html']; - } - - if (isset($loggingConfiguration['testdox-text']) && - !isset($arguments['testdoxTextFile'])) { - $arguments['testdoxTextFile'] = $loggingConfiguration['testdox-text']; - } - - if ((isset($arguments['coverageClover']) || - isset($arguments['reportDirectory']) || - isset($arguments['coveragePHP']) || - isset($arguments['coverageText'])) && - extension_loaded('xdebug')) { - - $filterConfiguration = $arguments['configuration']->getFilterConfiguration(); - $arguments['addUncoveredFilesFromWhitelist'] = $filterConfiguration['whitelist']['addUncoveredFilesFromWhitelist']; - $arguments['processUncoveredFilesFromWhitelist'] = $filterConfiguration['whitelist']['processUncoveredFilesFromWhitelist']; - - foreach ($filterConfiguration['blacklist']['include']['directory'] as $dir) { - $this->codeCoverageFilter->addDirectoryToBlacklist( - $dir['path'], $dir['suffix'], $dir['prefix'], $dir['group'] - ); - } - - foreach ($filterConfiguration['blacklist']['include']['file'] as $file) { - $this->codeCoverageFilter->addFileToBlacklist($file); - } - - foreach ($filterConfiguration['blacklist']['exclude']['directory'] as $dir) { - $this->codeCoverageFilter->removeDirectoryFromBlacklist( - $dir['path'], $dir['suffix'], $dir['prefix'], $dir['group'] - ); - } - - foreach ($filterConfiguration['blacklist']['exclude']['file'] as $file) { - $this->codeCoverageFilter->removeFileFromBlacklist($file); - } - - foreach ($filterConfiguration['whitelist']['include']['directory'] as $dir) { - $this->codeCoverageFilter->addDirectoryToWhitelist( - $dir['path'], $dir['suffix'], $dir['prefix'] - ); - } - - foreach ($filterConfiguration['whitelist']['include']['file'] as $file) { - $this->codeCoverageFilter->addFileToWhitelist($file); - } - - foreach ($filterConfiguration['whitelist']['exclude']['directory'] as $dir) { - $this->codeCoverageFilter->removeDirectoryFromWhitelist( - $dir['path'], $dir['suffix'], $dir['prefix'] - ); - } - - foreach ($filterConfiguration['whitelist']['exclude']['file'] as $file) { - $this->codeCoverageFilter->removeFileFromWhitelist($file); - } - } - } - - $arguments['addUncoveredFilesFromWhitelist'] = isset($arguments['addUncoveredFilesFromWhitelist']) ? $arguments['addUncoveredFilesFromWhitelist'] : TRUE; - $arguments['processUncoveredFilesFromWhitelist'] = isset($arguments['processUncoveredFilesFromWhitelist']) ? $arguments['processUncoveredFilesFromWhitelist'] : FALSE; - $arguments['backupGlobals'] = isset($arguments['backupGlobals']) ? $arguments['backupGlobals'] : NULL; - $arguments['backupStaticAttributes'] = isset($arguments['backupStaticAttributes']) ? $arguments['backupStaticAttributes'] : NULL; - $arguments['cacheTokens'] = isset($arguments['cacheTokens']) ? $arguments['cacheTokens'] : FALSE; - $arguments['colors'] = isset($arguments['colors']) ? $arguments['colors'] : FALSE; - $arguments['convertErrorsToExceptions'] = isset($arguments['convertErrorsToExceptions']) ? $arguments['convertErrorsToExceptions'] : TRUE; - $arguments['convertNoticesToExceptions'] = isset($arguments['convertNoticesToExceptions']) ? $arguments['convertNoticesToExceptions'] : TRUE; - $arguments['convertWarningsToExceptions'] = isset($arguments['convertWarningsToExceptions']) ? $arguments['convertWarningsToExceptions'] : TRUE; - $arguments['excludeGroups'] = isset($arguments['excludeGroups']) ? $arguments['excludeGroups'] : array(); - $arguments['groups'] = isset($arguments['groups']) ? $arguments['groups'] : array(); - $arguments['logIncompleteSkipped'] = isset($arguments['logIncompleteSkipped']) ? $arguments['logIncompleteSkipped'] : FALSE; - $arguments['processIsolation'] = isset($arguments['processIsolation']) ? $arguments['processIsolation'] : FALSE; - $arguments['repeat'] = isset($arguments['repeat']) ? $arguments['repeat'] : FALSE; - $arguments['reportCharset'] = isset($arguments['reportCharset']) ? $arguments['reportCharset'] : 'UTF-8'; - $arguments['reportHighlight'] = isset($arguments['reportHighlight']) ? $arguments['reportHighlight'] : FALSE; - $arguments['reportHighLowerBound'] = isset($arguments['reportHighLowerBound']) ? $arguments['reportHighLowerBound'] : 70; - $arguments['reportLowUpperBound'] = isset($arguments['reportLowUpperBound']) ? $arguments['reportLowUpperBound'] : 35; - $arguments['stopOnError'] = isset($arguments['stopOnError']) ? $arguments['stopOnError'] : FALSE; - $arguments['stopOnFailure'] = isset($arguments['stopOnFailure']) ? $arguments['stopOnFailure'] : FALSE; - $arguments['stopOnIncomplete'] = isset($arguments['stopOnIncomplete']) ? $arguments['stopOnIncomplete'] : FALSE; - $arguments['stopOnSkipped'] = isset($arguments['stopOnSkipped']) ? $arguments['stopOnSkipped'] : FALSE; - $arguments['timeoutForSmallTests'] = isset($arguments['timeoutForSmallTests']) ? $arguments['timeoutForSmallTests'] : 1; - $arguments['timeoutForMediumTests'] = isset($arguments['timeoutForMediumTests']) ? $arguments['timeoutForMediumTests'] : 10; - $arguments['timeoutForLargeTests'] = isset($arguments['timeoutForLargeTests']) ? $arguments['timeoutForLargeTests'] : 60; - $arguments['strict'] = isset($arguments['strict']) ? $arguments['strict'] : FALSE; - $arguments['verbose'] = isset($arguments['verbose']) ? $arguments['verbose'] : FALSE; - - if ($arguments['filter'] !== FALSE && - preg_match('/^[a-zA-Z0-9_]/', $arguments['filter'])) { - // Escape delimiters in regular expression. Do NOT use preg_quote, - // to keep magic characters. - $arguments['filter'] = '/' . str_replace( - '/', '\\/', $arguments['filter'] - ) . '/'; - } - } -} diff --git a/PHPUnit/Util/Configuration.php b/PHPUnit/Util/Configuration.php deleted file mode 100644 index 7ae700a0fc2..00000000000 --- a/PHPUnit/Util/Configuration.php +++ /dev/null @@ -1,1032 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.2.0 - */ - -/** - * Wrapper for the PHPUnit XML configuration file. - * - * Example XML configuration file: - * - * - * - * - * - * - * /path/to/files - * /path/to/MyTest.php - * /path/to/files/exclude - * - * - * - * - * - * name - * - * - * name - * - * - * - * - * - * /path/to/files - * /path/to/file - * - * /path/to/files - * /path/to/file - * - * - * - * /path/to/files - * /path/to/file - * - * /path/to/files - * /path/to/file - * - * - * - * - * - * - * - * - * - * Sebastian - * - * - * 22 - * April - * 19.78 - * - * - * MyRelativeFile.php - * MyRelativeDir - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * . - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.2.0 - */ -class PHPUnit_Util_Configuration -{ - private static $instances = array(); - - protected $document; - protected $xpath; - protected $filename; - - /** - * Loads a PHPUnit configuration file. - * - * @param string $filename - */ - protected function __construct($filename) - { - $this->filename = $filename; - $this->document = PHPUnit_Util_XML::loadFile($filename, FALSE, TRUE); - $this->xpath = new DOMXPath($this->document); - } - - /** - * @since Method available since Release 3.4.0 - */ - private final function __clone() - { - } - - /** - * Returns a PHPUnit configuration object. - * - * @param string $filename - * @return PHPUnit_Util_Configuration - * @since Method available since Release 3.4.0 - */ - public static function getInstance($filename) - { - $realpath = realpath($filename); - - if ($realpath === FALSE) { - throw new PHPUnit_Framework_Exception( - sprintf( - 'Could not read "%s".', - $filename - ) - ); - } - - if (!isset(self::$instances[$realpath])) { - self::$instances[$realpath] = new PHPUnit_Util_Configuration($realpath); - } - - return self::$instances[$realpath]; - } - - /** - * Returns the realpath to the configuration file. - * - * @return string - * @since Method available since Release 3.6.0 - */ - public function getFilename() - { - return $this->filename; - } - - /** - * Returns the configuration for SUT filtering. - * - * @return array - * @since Method available since Release 3.2.1 - */ - public function getFilterConfiguration() - { - $addUncoveredFilesFromWhitelist = TRUE; - $processUncoveredFilesFromWhitelist = FALSE; - - $tmp = $this->xpath->query('filter/whitelist'); - - if ($tmp->length == 1) { - if ($tmp->item(0)->hasAttribute('addUncoveredFilesFromWhitelist')) { - $addUncoveredFilesFromWhitelist = $this->getBoolean( - (string)$tmp->item(0)->getAttribute( - 'addUncoveredFilesFromWhitelist' - ), - TRUE - ); - } - - if ($tmp->item(0)->hasAttribute('processUncoveredFilesFromWhitelist')) { - $processUncoveredFilesFromWhitelist = $this->getBoolean( - (string)$tmp->item(0)->getAttribute( - 'processUncoveredFilesFromWhitelist' - ), - FALSE - ); - } - } - - return array( - 'blacklist' => array( - 'include' => array( - 'directory' => $this->readFilterDirectories( - 'filter/blacklist/directory' - ), - 'file' => $this->readFilterFiles( - 'filter/blacklist/file' - ) - ), - 'exclude' => array( - 'directory' => $this->readFilterDirectories( - 'filter/blacklist/exclude/directory' - ), - 'file' => $this->readFilterFiles( - 'filter/blacklist/exclude/file' - ) - ) - ), - 'whitelist' => array( - 'addUncoveredFilesFromWhitelist' => $addUncoveredFilesFromWhitelist, - 'processUncoveredFilesFromWhitelist' => $processUncoveredFilesFromWhitelist, - 'include' => array( - 'directory' => $this->readFilterDirectories( - 'filter/whitelist/directory' - ), - 'file' => $this->readFilterFiles( - 'filter/whitelist/file' - ) - ), - 'exclude' => array( - 'directory' => $this->readFilterDirectories( - 'filter/whitelist/exclude/directory' - ), - 'file' => $this->readFilterFiles( - 'filter/whitelist/exclude/file' - ) - ) - ) - ); - } - - /** - * Returns the configuration for groups. - * - * @return array - * @since Method available since Release 3.2.1 - */ - public function getGroupConfiguration() - { - $groups = array( - 'include' => array(), - 'exclude' => array() - ); - - foreach ($this->xpath->query('groups/include/group') as $group) { - $groups['include'][] = (string)$group->nodeValue; - } - - foreach ($this->xpath->query('groups/exclude/group') as $group) { - $groups['exclude'][] = (string)$group->nodeValue; - } - - return $groups; - } - - /** - * Returns the configuration for listeners. - * - * @return array - * @since Method available since Release 3.4.0 - */ - public function getListenerConfiguration() - { - $result = array(); - - foreach ($this->xpath->query('listeners/listener') as $listener) { - $class = (string)$listener->getAttribute('class'); - $file = ''; - $arguments = array(); - - if ($listener->hasAttribute('file')) { - $file = $this->toAbsolutePath( - (string)$listener->getAttribute('file'), TRUE - ); - } - - foreach ($listener->childNodes as $node) { - if ($node instanceof DOMElement && $node->tagName == 'arguments') { - foreach ($node->childNodes as $argument) { - if ($argument instanceof DOMElement) { - if ($argument->tagName == 'file' || - $argument->tagName == 'directory') { - $arguments[] = $this->toAbsolutePath((string)$argument->nodeValue); - } else { - $arguments[] = PHPUnit_Util_XML::xmlToVariable($argument); - } - } - } - } - } - - $result[] = array( - 'class' => $class, - 'file' => $file, - 'arguments' => $arguments - ); - } - - return $result; - } - - /** - * Returns the logging configuration. - * - * @return array - */ - public function getLoggingConfiguration() - { - $result = array(); - - foreach ($this->xpath->query('logging/log') as $log) { - $type = (string)$log->getAttribute('type'); - - $target = $this->toAbsolutePath( - (string)$log->getAttribute('target') - ); - - if ($type == 'coverage-html') { - if ($log->hasAttribute('title')) { - $result['title'] = (string)$log->getAttribute('title'); - } - - if ($log->hasAttribute('charset')) { - $result['charset'] = (string)$log->getAttribute('charset'); - } - - if ($log->hasAttribute('lowUpperBound')) { - $result['lowUpperBound'] = (string)$log->getAttribute('lowUpperBound'); - } - - if ($log->hasAttribute('highLowerBound')) { - $result['highLowerBound'] = (string)$log->getAttribute('highLowerBound'); - } - - if ($log->hasAttribute('highlight')) { - $result['highlight'] = $this->getBoolean( - (string)$log->getAttribute('highlight'), - FALSE - ); - } - } - - else if ($type == 'junit') { - if ($log->hasAttribute('logIncompleteSkipped')) { - $result['logIncompleteSkipped'] = $this->getBoolean( - (string)$log->getAttribute('logIncompleteSkipped'), - FALSE - ); - } - } - - else if ($type == 'coverage-text') { - if ($log->hasAttribute('showUncoveredFiles')) { - $result['coverageTextShowUncoveredFiles'] = $this->getBoolean( - (string)$log->getAttribute('showUncoveredFiles'), - FALSE - ); - } - if ($log->hasAttribute('showOnlySummary')) { - $result['coverageTextShowOnlySummary'] = $this->getBoolean( - (string)$log->getAttribute('showOnlySummary'), - FALSE - ); - } - } - - $result[$type] = $target; - } - - return $result; - } - - /** - * Returns the PHP configuration. - * - * @return array - * @since Method available since Release 3.2.1 - */ - public function getPHPConfiguration() - { - $result = array( - 'include_path' => array(), - 'ini' => array(), - 'const' => array(), - 'var' => array(), - 'env' => array(), - 'post' => array(), - 'get' => array(), - 'cookie' => array(), - 'server' => array(), - 'files' => array(), - 'request' => array() - ); - - foreach ($this->xpath->query('php/includePath') as $includePath) { - $path = (string)$includePath->nodeValue; - - $result['include_path'][] = $this->toAbsolutePath($path); - } - - foreach ($this->xpath->query('php/ini') as $ini) { - $name = (string)$ini->getAttribute('name'); - $value = (string)$ini->getAttribute('value'); - - $result['ini'][$name] = $value; - } - - foreach ($this->xpath->query('php/const') as $const) { - $name = (string)$const->getAttribute('name'); - $value = (string)$const->getAttribute('value'); - - $result['const'][$name] = $this->getBoolean($value, $value); - } - - foreach (array('var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) { - foreach ($this->xpath->query('php/' . $array) as $var) { - $name = (string)$var->getAttribute('name'); - $value = (string)$var->getAttribute('value'); - - $result[$array][$name] = $this->getBoolean($value, $value); - } - } - - return $result; - } - - /** - * Handles the PHP configuration. - * - * @since Method available since Release 3.2.20 - */ - public function handlePHPConfiguration() - { - $configuration = $this->getPHPConfiguration(); - - if (! empty($configuration['include_path'])) { - ini_set( - 'include_path', - implode(PATH_SEPARATOR, $configuration['include_path']) . - PATH_SEPARATOR . - ini_get('include_path') - ); - } - - foreach ($configuration['ini'] as $name => $value) { - if (defined($value)) { - $value = constant($value); - } - - ini_set($name, $value); - } - - foreach ($configuration['const'] as $name => $value) { - if (!defined($name)) { - define($name, $value); - } - } - - foreach (array('var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request') as $array) { - if ($array == 'var') { - $target = &$GLOBALS; - } else { - $target = &$GLOBALS['_' . strtoupper($array)]; - } - - foreach ($configuration[$array] as $name => $value) { - $target[$name] = $value; - } - } - - foreach ($configuration['env'] as $name => $value) { - putenv("$name=$value"); - } - } - - /** - * Returns the PHPUnit configuration. - * - * @return array - * @since Method available since Release 3.2.14 - */ - public function getPHPUnitConfiguration() - { - $result = array(); - $root = $this->document->documentElement; - - if ($root->hasAttribute('cacheTokens')) { - $result['cacheTokens'] = $this->getBoolean( - (string)$root->getAttribute('cacheTokens'), FALSE - ); - } - - if ($root->hasAttribute('colors')) { - $result['colors'] = $this->getBoolean( - (string)$root->getAttribute('colors'), FALSE - ); - } - - if ($root->hasAttribute('backupGlobals')) { - $result['backupGlobals'] = $this->getBoolean( - (string)$root->getAttribute('backupGlobals'), TRUE - ); - } - - if ($root->hasAttribute('backupStaticAttributes')) { - $result['backupStaticAttributes'] = $this->getBoolean( - (string)$root->getAttribute('backupStaticAttributes'), FALSE - ); - } - - if ($root->hasAttribute('bootstrap')) { - $result['bootstrap'] = $this->toAbsolutePath( - (string)$root->getAttribute('bootstrap') - ); - } - - if ($root->hasAttribute('convertErrorsToExceptions')) { - $result['convertErrorsToExceptions'] = $this->getBoolean( - (string)$root->getAttribute('convertErrorsToExceptions'), TRUE - ); - } - - if ($root->hasAttribute('convertNoticesToExceptions')) { - $result['convertNoticesToExceptions'] = $this->getBoolean( - (string)$root->getAttribute('convertNoticesToExceptions'), TRUE - ); - } - - if ($root->hasAttribute('convertWarningsToExceptions')) { - $result['convertWarningsToExceptions'] = $this->getBoolean( - (string)$root->getAttribute('convertWarningsToExceptions'), TRUE - ); - } - - if ($root->hasAttribute('forceCoversAnnotation')) { - $result['forceCoversAnnotation'] = $this->getBoolean( - (string)$root->getAttribute('forceCoversAnnotation'), FALSE - ); - } - - if ($root->hasAttribute('mapTestClassNameToCoveredClassName')) { - $result['mapTestClassNameToCoveredClassName'] = $this->getBoolean( - (string)$root->getAttribute('mapTestClassNameToCoveredClassName'), - FALSE - ); - } - - if ($root->hasAttribute('processIsolation')) { - $result['processIsolation'] = $this->getBoolean( - (string)$root->getAttribute('processIsolation'), FALSE - ); - } - - if ($root->hasAttribute('stopOnError')) { - $result['stopOnError'] = $this->getBoolean( - (string)$root->getAttribute('stopOnError'), FALSE - ); - } - - if ($root->hasAttribute('stopOnFailure')) { - $result['stopOnFailure'] = $this->getBoolean( - (string)$root->getAttribute('stopOnFailure'), FALSE - ); - } - - if ($root->hasAttribute('stopOnIncomplete')) { - $result['stopOnIncomplete'] = $this->getBoolean( - (string)$root->getAttribute('stopOnIncomplete'), FALSE - ); - } - - if ($root->hasAttribute('stopOnSkipped')) { - $result['stopOnSkipped'] = $this->getBoolean( - (string)$root->getAttribute('stopOnSkipped'), FALSE - ); - } - - if ($root->hasAttribute('testSuiteLoaderClass')) { - $result['testSuiteLoaderClass'] = (string)$root->getAttribute( - 'testSuiteLoaderClass' - ); - } - - if ($root->hasAttribute('testSuiteLoaderFile')) { - $result['testSuiteLoaderFile'] = (string)$root->getAttribute( - 'testSuiteLoaderFile' - ); - } - - if ($root->hasAttribute('printerClass')) { - $result['printerClass'] = (string)$root->getAttribute( - 'printerClass' - ); - } - - if ($root->hasAttribute('printerFile')) { - $result['printerFile'] = (string)$root->getAttribute( - 'printerFile' - ); - } - - if ($root->hasAttribute('timeoutForSmallTests')) { - $result['timeoutForSmallTests'] = $this->getInteger( - (string)$root->getAttribute('timeoutForSmallTests'), 1 - ); - } - - if ($root->hasAttribute('timeoutForMediumTests')) { - $result['timeoutForMediumTests'] = $this->getInteger( - (string)$root->getAttribute('timeoutForMediumTests'), 10 - ); - } - - if ($root->hasAttribute('timeoutForLargeTests')) { - $result['timeoutForLargeTests'] = $this->getInteger( - (string)$root->getAttribute('timeoutForLargeTests'), 60 - ); - } - - if ($root->hasAttribute('strict')) { - $result['strict'] = $this->getBoolean( - (string)$root->getAttribute('strict'), FALSE - ); - } - - if ($root->hasAttribute('verbose')) { - $result['verbose'] = $this->getBoolean( - (string)$root->getAttribute('verbose'), FALSE - ); - } - - return $result; - } - - /** - * Returns the SeleniumTestCase browser configuration. - * - * @return array - * @since Method available since Release 3.2.9 - */ - public function getSeleniumBrowserConfiguration() - { - $result = array(); - - foreach ($this->xpath->query('selenium/browser') as $config) { - $name = (string)$config->getAttribute('name'); - $browser = (string)$config->getAttribute('browser'); - - if ($config->hasAttribute('host')) { - $host = (string)$config->getAttribute('host'); - } else { - $host = 'localhost'; - } - - if ($config->hasAttribute('port')) { - $port = $this->getInteger( - (string)$config->getAttribute('port'), 4444 - ); - } else { - $port = 4444; - } - - if ($config->hasAttribute('timeout')) { - $timeout = $this->getInteger( - (string)$config->getAttribute('timeout'), 30000 - ); - } else { - $timeout = 30000; - } - - $result[] = array( - 'name' => $name, - 'browser' => $browser, - 'host' => $host, - 'port' => $port, - 'timeout' => $timeout - ); - } - - return $result; - } - - /** - * Returns the test suite configuration. - * - * @return PHPUnit_Framework_TestSuite - * @since Method available since Release 3.2.1 - */ - public function getTestSuiteConfiguration($testSuiteFilter=null) - { - $testSuiteNodes = $this->xpath->query('testsuites/testsuite'); - - if ($testSuiteNodes->length == 0) { - $testSuiteNodes = $this->xpath->query('testsuite'); - } - - if ($testSuiteNodes->length == 1) { - return $this->getTestSuite($testSuiteNodes->item(0), $testSuiteFilter); - } - - if ($testSuiteNodes->length > 1) { - $suite = new PHPUnit_Framework_TestSuite; - - foreach ($testSuiteNodes as $testSuiteNode) { - $suite->addTestSuite( - $this->getTestSuite($testSuiteNode, $testSuiteFilter) - ); - } - - return $suite; - } - } - - /** - * @param DOMElement $testSuiteNode - * @return PHPUnit_Framework_TestSuite - * @since Method available since Release 3.4.0 - */ - protected function getTestSuite(DOMElement $testSuiteNode, $testSuiteFilter=null) - { - if ($testSuiteNode->hasAttribute('name')) { - $suite = new PHPUnit_Framework_TestSuite( - (string)$testSuiteNode->getAttribute('name') - ); - } else { - $suite = new PHPUnit_Framework_TestSuite; - } - - $exclude = array(); - - foreach ($testSuiteNode->getElementsByTagName('exclude') as $excludeNode) { - $exclude[] = (string)$excludeNode->nodeValue; - } - - $fileIteratorFacade = new File_Iterator_Facade; - - foreach ($testSuiteNode->getElementsByTagName('directory') as $directoryNode) { - if ($testSuiteFilter && $directoryNode->parentNode->getAttribute('name') != $testSuiteFilter) { - continue; - } - - $directory = (string)$directoryNode->nodeValue; - - if (empty($directory)) { - continue; - } - - if ($directoryNode->hasAttribute('phpVersion')) { - $phpVersion = (string)$directoryNode->getAttribute('phpVersion'); - } else { - $phpVersion = PHP_VERSION; - } - - if ($directoryNode->hasAttribute('phpVersionOperator')) { - $phpVersionOperator = (string)$directoryNode->getAttribute('phpVersionOperator'); - } else { - $phpVersionOperator = '>='; - } - - if (!version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) { - continue; - } - - if ($directoryNode->hasAttribute('prefix')) { - $prefix = (string)$directoryNode->getAttribute('prefix'); - } else { - $prefix = ''; - } - - if ($directoryNode->hasAttribute('suffix')) { - $suffix = (string)$directoryNode->getAttribute('suffix'); - } else { - $suffix = 'Test.php'; - } - - $files = $fileIteratorFacade->getFilesAsArray( - $this->toAbsolutePath($directory), - $suffix, - $prefix, - $exclude - ); - $suite->addTestFiles($files); - } - - foreach ($testSuiteNode->getElementsByTagName('file') as $fileNode) { - if ($testSuiteFilter && $fileNode->parentNode->getAttribute('name') != $testSuiteFilter) { - continue; - } - - $file = (string)$fileNode->nodeValue; - - if (empty($file)) { - continue; - } - - // Get the absolute path to the file - $file = $fileIteratorFacade->getFilesAsArray($file); - - if (!isset($file[0])) { - continue; - } - - $file = $file[0]; - - if ($fileNode->hasAttribute('phpVersion')) { - $phpVersion = (string)$fileNode->getAttribute('phpVersion'); - } else { - $phpVersion = PHP_VERSION; - } - - if ($fileNode->hasAttribute('phpVersionOperator')) { - $phpVersionOperator = (string)$fileNode->getAttribute('phpVersionOperator'); - } else { - $phpVersionOperator = '>='; - } - - if (!version_compare(PHP_VERSION, $phpVersion, $phpVersionOperator)) { - continue; - } - - $suite->addTestFile($file); - } - - return $suite; - } - - /** - * @param string $value - * @param boolean $default - * @return boolean - * @since Method available since Release 3.2.3 - */ - protected function getBoolean($value, $default) - { - if (strtolower($value) == 'false') { - return FALSE; - } - - else if (strtolower($value) == 'true') { - return TRUE; - } - - return $default; - } - - /** - * @param string $value - * @param boolean $default - * @return boolean - * @since Method available since Release 3.6.0 - */ - protected function getInteger($value, $default) - { - if (is_numeric($value)) { - return (int)$value; - } - - return $default; - } - - /** - * @param string $query - * @return array - * @since Method available since Release 3.2.3 - */ - protected function readFilterDirectories($query) - { - $directories = array(); - - foreach ($this->xpath->query($query) as $directory) { - if ($directory->hasAttribute('prefix')) { - $prefix = (string)$directory->getAttribute('prefix'); - } else { - $prefix = ''; - } - - if ($directory->hasAttribute('suffix')) { - $suffix = (string)$directory->getAttribute('suffix'); - } else { - $suffix = '.php'; - } - - if ($directory->hasAttribute('group')) { - $group = (string)$directory->getAttribute('group'); - } else { - $group = 'DEFAULT'; - } - - $directories[] = array( - 'path' => $this->toAbsolutePath((string)$directory->nodeValue), - 'prefix' => $prefix, - 'suffix' => $suffix, - 'group' => $group - ); - } - - return $directories; - } - - /** - * @param string $query - * @return array - * @since Method available since Release 3.2.3 - */ - protected function readFilterFiles($query) - { - $files = array(); - - foreach ($this->xpath->query($query) as $file) { - $files[] = $this->toAbsolutePath((string)$file->nodeValue); - } - - return $files; - } - - /** - * @param string $path - * @param boolean $useIncludePath - * @return string - * @since Method available since Release 3.5.0 - */ - protected function toAbsolutePath($path, $useIncludePath = FALSE) - { - // Check whether the path is already absolute. - if ($path[0] === '/' || $path[0] === '\\' || - (strlen($path) > 3 && ctype_alpha($path[0]) && - $path[1] === ':' && ($path[2] === '\\' || $path[2] === '/'))) { - return $path; - } - - // Check whether a stream is used. - if (strpos($path, '://') !== FALSE) { - return $path; - } - - $file = dirname($this->filename) . DIRECTORY_SEPARATOR . $path; - - if ($useIncludePath && !file_exists($file)) { - $includePathFile = stream_resolve_include_path($path); - - if ($includePathFile) { - $file = $includePathFile; - } - } - - return $file; - } -} diff --git a/PHPUnit/Util/DeprecatedFeature.php b/PHPUnit/Util/DeprecatedFeature.php deleted file mode 100644 index ee3f0329d32..00000000000 --- a/PHPUnit/Util/DeprecatedFeature.php +++ /dev/null @@ -1,102 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Ralph Schindler - * @author Sebastian Bergmann - * @copyright 2002-2010 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.7 - */ - -/** - * Class to hold the information about a deprecated feature that was used - * - * @package PHPUnit - * @subpackage Framework - * @author Ralph Schindler - * @author Sebastian Bergmann - * @copyright 2002-2010 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Interface available since Release 3.5.7 - */ -class PHPUnit_Util_DeprecatedFeature -{ - /** - * @var array - */ - protected $traceInfo = array(); - - /** - * @var string - */ - protected $message = NULL; - - /** - * @param string $message - * @param array $traceInfo - */ - public function __construct($message, array $traceInfo = array()) - { - $this->message = $message; - $this->traceInfo = $traceInfo; - } - - /** - * Build a string representation of the deprecated feature that was raised - * - * @return string - */ - public function __toString() - { - $string = ''; - - if (isset($this->traceInfo['file'])) { - $string .= $this->traceInfo['file']; - - if (isset($this->traceInfo['line'])) { - $string .= ':' . $this->traceInfo['line'] . ' - '; - } - } - - $string .= $this->message; - - return $string; - } -} diff --git a/PHPUnit/Util/DeprecatedFeature/Logger.php b/PHPUnit/Util/DeprecatedFeature/Logger.php deleted file mode 100644 index 721bdffec67..00000000000 --- a/PHPUnit/Util/DeprecatedFeature/Logger.php +++ /dev/null @@ -1,201 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Framework - * @author Ralph Schindler - * @author Sebastian Bergmann - * @copyright 2002-2010 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.7 - */ - -/** - * Test Listener that tracks the usage of deprecated features. - * - * @package PHPUnit - * @subpackage Framework - * @author Ralph Schindler - * @author Sebastian Bergmann - * @copyright 2002-2010 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.7 - */ -class PHPUnit_Util_DeprecatedFeature_Logger implements PHPUnit_Framework_TestListener -{ - /** - * @var PHPUnit_Framework_TestCase - */ - protected static $currentTest = NULL; - - /** - * This is the publically accessible API for notifying the system that a - * deprecated feature has been used. - * - * If it is run via a TestRunner and the test extends - * PHPUnit_Framework_TestCase, then this will inject the result into the - * test runner for display, if not, it will throw the notice to STDERR. - * - * @param string $message - * @param int|bool $backtraceDepth - */ - public static function log($message, $backtraceDepth = 2) - { - if ($backtraceDepth !== FALSE) { - $trace = debug_backtrace(FALSE); - - if (is_int($backtraceDepth)) { - $traceItem = $trace[$backtraceDepth]; - } - - if (!isset($traceItem['file'])) { - $reflectionClass = new ReflectionClass($traceItem['class']); - $traceItem['file'] = $reflectionClass->getFileName(); - } - - if (!isset($traceItem['line']) && - isset($traceItem['class']) && - isset($traceItem['function'])) { - if (!isset($reflectionClass)) { - $reflectionClass = new ReflectionClass($traceItem['class']); - } - - $method = $reflectionClass->getMethod($traceItem['function']); - $traceItem['line'] = '(between ' . $method->getStartLine() . - ' and ' . $method->getEndLine() . ')'; - } - } - - $deprecatedFeature = new PHPUnit_Util_DeprecatedFeature( - $message, $traceItem - ); - - if (self::$currentTest instanceof PHPUnit_Framework_TestCase) { - $result = self::$currentTest->getTestResultObject(); - $result->addDeprecatedFeature($deprecatedFeature); - } else { - file_put_contents('php://stderr', $deprecatedFeature); - } - } - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - } - - /** - * A test suite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test suite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - self::$currentTest = $test; - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - self::$currentTest = NULL; - } -} diff --git a/PHPUnit/Util/ErrorHandler.php b/PHPUnit/Util/ErrorHandler.php deleted file mode 100644 index fb15d69319d..00000000000 --- a/PHPUnit/Util/ErrorHandler.php +++ /dev/null @@ -1,132 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -// Workaround for http://bugs.php.net/bug.php?id=47987, -// see https://github.com/sebastianbergmann/phpunit/issues#issue/125 for details -require_once 'PHPUnit/Framework/Error.php'; -require_once 'PHPUnit/Framework/Error/Notice.php'; -require_once 'PHPUnit/Framework/Error/Warning.php'; -require_once 'PHPUnit/Framework/Error/Deprecated.php'; - -/** - * Error handler that converts PHP errors and warnings to exceptions. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class PHPUnit_Util_ErrorHandler -{ - protected static $errorStack = array(); - - /** - * Returns the error stack. - * - * @return array - */ - public static function getErrorStack() - { - return self::$errorStack; - } - - /** - * @param integer $errno - * @param string $errstr - * @param string $errfile - * @param integer $errline - * @throws PHPUnit_Framework_Error - */ - public static function handleError($errno, $errstr, $errfile, $errline) - { - if (!($errno & error_reporting())) { - return FALSE; - } - - self::$errorStack[] = array($errno, $errstr, $errfile, $errline); - - $trace = debug_backtrace(FALSE); - array_shift($trace); - - foreach ($trace as $frame) { - if ($frame['function'] == '__toString') { - return FALSE; - } - } - - if ($errno == E_NOTICE || $errno == E_USER_NOTICE || $errno == E_STRICT) { - if (PHPUnit_Framework_Error_Notice::$enabled !== TRUE) { - return FALSE; - } - - $exception = 'PHPUnit_Framework_Error_Notice'; - } - - else if ($errno == E_WARNING || $errno == E_USER_WARNING) { - if (PHPUnit_Framework_Error_Warning::$enabled !== TRUE) { - return FALSE; - } - - $exception = 'PHPUnit_Framework_Error_Warning'; - } - - else if ($errno == E_DEPRECATED || $errno == E_USER_DEPRECATED) { - if (PHPUnit_Framework_Error_Deprecated::$enabled !== TRUE) { - return FALSE; - } - - $exception = 'PHPUnit_Framework_Error_Deprecated'; - } - - else { - $exception = 'PHPUnit_Framework_Error'; - } - - throw new $exception($errstr, $errno, $errfile, $errline); - } -} diff --git a/PHPUnit/Util/Fileloader.php b/PHPUnit/Util/Fileloader.php deleted file mode 100644 index 425861d4f0b..00000000000 --- a/PHPUnit/Util/Fileloader.php +++ /dev/null @@ -1,108 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * Utility methods to load PHP sourcefiles. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.3.0 - */ -class PHPUnit_Util_Fileloader -{ - /** - * Checks if a PHP sourcefile is readable. - * The sourcefile is loaded through the load() method. - * - * @param string $filename - * @return string - * @throws PHPUnit_Framework_Exception - */ - public static function checkAndLoad($filename) - { - $includePathFilename = stream_resolve_include_path($filename); - - if (!$includePathFilename || !is_readable($includePathFilename)) { - throw new PHPUnit_Framework_Exception( - sprintf('Cannot open file "%s".' . "\n", $filename) - ); - } - - self::load($includePathFilename); - - return $includePathFilename; - } - - /** - * Loads a PHP sourcefile. - * - * @param string $filename - * @return mixed - * @since Method available since Release 3.0.0 - */ - public static function load($filename) - { - $oldVariableNames = array_keys(get_defined_vars()); - - include_once $filename; - - $newVariables = get_defined_vars(); - $newVariableNames = array_diff( - array_keys($newVariables), $oldVariableNames - ); - - foreach ($newVariableNames as $variableName) { - if ($variableName != 'oldVariableNames') { - $GLOBALS[$variableName] = $newVariables[$variableName]; - } - } - - return $filename; - } -} diff --git a/PHPUnit/Util/Filesystem.php b/PHPUnit/Util/Filesystem.php deleted file mode 100644 index 63b60457b95..00000000000 --- a/PHPUnit/Util/Filesystem.php +++ /dev/null @@ -1,81 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Filesystem helpers. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Filesystem -{ - /** - * @var array - */ - protected static $buffer = array(); - - /** - * Maps class names to source file names: - * - PEAR CS: Foo_Bar_Baz -> Foo/Bar/Baz.php - * - Namespace: Foo\Bar\Baz -> Foo/Bar/Baz.php - * - * @param string $className - * @return string - * @since Method available since Release 3.4.0 - */ - public static function classNameToFilename($className) - { - return str_replace( - array('_', '\\'), - DIRECTORY_SEPARATOR, - $className - ) . '.php'; - } -} diff --git a/PHPUnit/Util/Filter.php b/PHPUnit/Util/Filter.php deleted file mode 100644 index f6dd7e49497..00000000000 --- a/PHPUnit/Util/Filter.php +++ /dev/null @@ -1,146 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Utility class for code filtering. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Util_Filter -{ - /** - * Filters stack frames from PHPUnit classes. - * - * @param Exception $e - * @param boolean $asString - * @return string - */ - public static function getFilteredStacktrace(Exception $e, $asString = TRUE) - { - $prefix = FALSE; - $script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']); - - if (defined('__PHPUNIT_PHAR__')) { - $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/'; - } - - if (!defined('PHPUNIT_TESTSUITE')) { - $blacklist = PHPUnit_Util_GlobalState::phpunitFiles(); - } else { - $blacklist = array(); - } - - if ($asString === TRUE) { - $filteredStacktrace = ''; - } else { - $filteredStacktrace = array(); - } - - if ($e instanceof PHPUnit_Framework_SyntheticError) { - $eTrace = $e->getSyntheticTrace(); - $eFile = $e->getSyntheticFile(); - $eLine = $e->getSyntheticLine(); - } else { - if ($e->getPrevious()) { - $eTrace = $e->getPrevious()->getTrace(); - } else { - $eTrace = $e->getTrace(); - } - $eFile = $e->getFile(); - $eLine = $e->getLine(); - } - - if (!self::frameExists($eTrace, $eFile, $eLine)) { - array_unshift( - $eTrace, array('file' => $eFile, 'line' => $eLine) - ); - } - - foreach ($eTrace as $frame) { - if (isset($frame['file']) && is_file($frame['file']) && - !isset($blacklist[$frame['file']]) && - strpos($frame['file'], $prefix) !== 0 && - $frame['file'] !== $script) { - if ($asString === TRUE) { - $filteredStacktrace .= sprintf( - "%s:%s\n", - - $frame['file'], - isset($frame['line']) ? $frame['line'] : '?' - ); - } else { - $filteredStacktrace[] = $frame; - } - } - } - - return $filteredStacktrace; - } - - /** - * @param array $trace - * @param string $file - * @param int $line - * @return boolean - * @since Method available since Release 3.3.2 - */ - public static function frameExists(array $trace, $file, $line) - { - foreach ($trace as $frame) { - if (isset($frame['file']) && $frame['file'] == $file && - isset($frame['line']) && $frame['line'] == $line) { - return TRUE; - } - } - - return FALSE; - } -} diff --git a/PHPUnit/Util/Getopt.php b/PHPUnit/Util/Getopt.php deleted file mode 100644 index be8682308e3..00000000000 --- a/PHPUnit/Util/Getopt.php +++ /dev/null @@ -1,207 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Command-line options parsing class. - * - * @package PHPUnit - * @subpackage Util - * @author Andrei Zmievski - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Getopt -{ - public static function getopt(array $args, $short_options, $long_options = NULL) - { - if (empty($args)) { - return array(array(), array()); - } - - $opts = array(); - $non_opts = array(); - - if ($long_options) { - sort($long_options); - } - - if (isset($args[0][0]) && $args[0][0] != '-') { - array_shift($args); - } - - reset($args); - array_map('trim', $args); - - while (list($i, $arg) = each($args)) { - if ($arg == '') { - continue; - } - - if ($arg == '--') { - $non_opts = array_merge($non_opts, array_slice($args, $i + 1)); - break; - } - - if ($arg[0] != '-' || - (strlen($arg) > 1 && $arg[1] == '-' && !$long_options)) { - $non_opts = array_merge($non_opts, array_slice($args, $i)); - break; - } - - elseif (strlen($arg) > 1 && $arg[1] == '-') { - self::parseLongOption( - substr($arg, 2), $long_options, $opts, $args - ); - } - - else { - self::parseShortOption( - substr($arg, 1), $short_options, $opts, $args - ); - } - } - - return array($opts, $non_opts); - } - - protected static function parseShortOption($arg, $short_options, &$opts, &$args) - { - $argLen = strlen($arg); - - for ($i = 0; $i < $argLen; $i++) { - $opt = $arg[$i]; - $opt_arg = NULL; - - if (($spec = strstr($short_options, $opt)) === FALSE || - $arg[$i] == ':') { - throw new PHPUnit_Framework_Exception( - "unrecognized option -- $opt" - ); - } - - if (strlen($spec) > 1 && $spec[1] == ':') { - if (strlen($spec) > 2 && $spec[2] == ':') { - if ($i + 1 < $argLen) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - } else { - if ($i + 1 < $argLen) { - $opts[] = array($opt, substr($arg, $i + 1)); - break; - } - - else if (list(, $opt_arg) = each($args)) { - } - - else { - throw new PHPUnit_Framework_Exception( - "option requires an argument -- $opt" - ); - } - } - } - - $opts[] = array($opt, $opt_arg); - } - } - - protected static function parseLongOption($arg, $long_options, &$opts, &$args) - { - $count = count($long_options); - $list = explode('=', $arg); - $opt = $list[0]; - $opt_arg = NULL; - - if (count($list) > 1) { - $opt_arg = $list[1]; - } - - $opt_len = strlen($opt); - - for ($i = 0; $i < $count; $i++) { - $long_opt = $long_options[$i]; - $opt_start = substr($long_opt, 0, $opt_len); - - if ($opt_start != $opt) { - continue; - } - - $opt_rest = substr($long_opt, $opt_len); - - if ($opt_rest != '' && $opt[0] != '=' && $i + 1 < $count && - $opt == substr($long_options[$i+1], 0, $opt_len)) { - throw new PHPUnit_Framework_Exception( - "option --$opt is ambiguous" - ); - } - - if (substr($long_opt, -1) == '=') { - if (substr($long_opt, -2) != '==') { - if (!strlen($opt_arg) && - !(list(, $opt_arg) = each($args))) { - throw new PHPUnit_Framework_Exception( - "option --$opt requires an argument" - ); - } - } - } - - else if ($opt_arg) { - throw new PHPUnit_Framework_Exception( - "option --$opt doesn't allow an argument" - ); - } - - $opts[] = array('--' . $opt, $opt_arg); - return; - } - - throw new PHPUnit_Framework_Exception("unrecognized option --$opt"); - } -} diff --git a/PHPUnit/Util/GlobalState.php b/PHPUnit/Util/GlobalState.php deleted file mode 100644 index 3d677f5c8bf..00000000000 --- a/PHPUnit/Util/GlobalState.php +++ /dev/null @@ -1,445 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Util_GlobalState -{ - /** - * @var array - */ - protected static $globals = array(); - - /** - * @var array - */ - protected static $staticAttributes = array(); - - /** - * @var array - */ - protected static $superGlobalArrays = array( - '_ENV', - '_POST', - '_GET', - '_COOKIE', - '_SERVER', - '_FILES', - '_REQUEST' - ); - - /** - * @var array - */ - protected static $superGlobalArraysLong = array( - 'HTTP_ENV_VARS', - 'HTTP_POST_VARS', - 'HTTP_GET_VARS', - 'HTTP_COOKIE_VARS', - 'HTTP_SERVER_VARS', - 'HTTP_POST_FILES' - ); - - /** - * @var array - */ - protected static $phpunitFiles; - - public static function backupGlobals(array $blacklist) - { - self::$globals = array(); - $superGlobalArrays = self::getSuperGlobalArrays(); - - foreach ($superGlobalArrays as $superGlobalArray) { - if (!in_array($superGlobalArray, $blacklist)) { - self::backupSuperGlobalArray($superGlobalArray); - } - } - - foreach (array_keys($GLOBALS) as $key) { - if ($key != 'GLOBALS' && - !in_array($key, $superGlobalArrays) && - !in_array($key, $blacklist) && - !$GLOBALS[$key] instanceof Closure) { - self::$globals['GLOBALS'][$key] = serialize($GLOBALS[$key]); - } - } - } - - public static function restoreGlobals(array $blacklist) - { - if (ini_get('register_long_arrays') == '1') { - $superGlobalArrays = array_merge( - self::$superGlobalArrays, self::$superGlobalArraysLong - ); - } else { - $superGlobalArrays = self::$superGlobalArrays; - } - - foreach ($superGlobalArrays as $superGlobalArray) { - if (!in_array($superGlobalArray, $blacklist)) { - self::restoreSuperGlobalArray($superGlobalArray); - } - } - - foreach (array_keys($GLOBALS) as $key) { - if ($key != 'GLOBALS' && - !in_array($key, $superGlobalArrays) && - !in_array($key, $blacklist)) { - if (isset(self::$globals['GLOBALS'][$key])) { - $GLOBALS[$key] = unserialize( - self::$globals['GLOBALS'][$key] - ); - } else { - unset($GLOBALS[$key]); - } - } - } - - self::$globals = array(); - } - - protected static function backupSuperGlobalArray($superGlobalArray) - { - self::$globals[$superGlobalArray] = array(); - - if (isset($GLOBALS[$superGlobalArray]) && - is_array($GLOBALS[$superGlobalArray])) { - foreach ($GLOBALS[$superGlobalArray] as $key => $value) { - self::$globals[$superGlobalArray][$key] = serialize($value); - } - } - } - - protected static function restoreSuperGlobalArray($superGlobalArray) - { - if (isset($GLOBALS[$superGlobalArray]) && - is_array($GLOBALS[$superGlobalArray]) && - isset(self::$globals[$superGlobalArray])) { - $keys = array_keys( - array_merge( - $GLOBALS[$superGlobalArray], self::$globals[$superGlobalArray] - ) - ); - - foreach ($keys as $key) { - if (isset(self::$globals[$superGlobalArray][$key])) { - $GLOBALS[$superGlobalArray][$key] = unserialize( - self::$globals[$superGlobalArray][$key] - ); - } else { - unset($GLOBALS[$superGlobalArray][$key]); - } - } - } - - self::$globals[$superGlobalArray] = array(); - } - - public static function getIncludedFilesAsString() - { - $blacklist = self::phpunitFiles(); - $files = get_included_files(); - $prefix = FALSE; - $result = ''; - - if (defined('__PHPUNIT_PHAR__')) { - $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/'; - } - - for ($i = count($files) - 1; $i > 0; $i--) { - $file = $files[$i]; - - if ($prefix !== FALSE) { - $file = str_replace($prefix, '', $file); - } - - if (!isset($blacklist[$file]) && is_file($file)) { - $result = 'require_once \'' . $file . "';\n" . $result; - } - } - - return $result; - } - - public static function getIniSettingsAsString() - { - $result = ''; - $iniSettings = ini_get_all(null, FALSE); - - foreach ($iniSettings as $key => $value) { - $result .= sprintf( - 'ini_set(%s, %s);' . "\n", - self::exportVariable($key), - self::exportVariable($value) - ); - } - - return $result; - } - - public static function getConstantsAsString() - { - $constants = get_defined_constants(TRUE); - $result = ''; - - if (isset($constants['user'])) { - foreach ($constants['user'] as $name => $value) { - $result .= sprintf( - 'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", - $name, - $name, - self::exportVariable($value) - ); - } - } - - return $result; - } - - public static function getGlobalsAsString() - { - $result = ''; - $superGlobalArrays = self::getSuperGlobalArrays(); - - foreach ($superGlobalArrays as $superGlobalArray) { - if (isset($GLOBALS[$superGlobalArray]) && - is_array($GLOBALS[$superGlobalArray])) { - foreach (array_keys($GLOBALS[$superGlobalArray]) as $key) { - if ($GLOBALS[$superGlobalArray][$key] instanceof Closure) { - continue; - } - - $result .= sprintf( - '$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n", - $superGlobalArray, - $key, - self::exportVariable($GLOBALS[$superGlobalArray][$key]) - ); - } - } - } - - $blacklist = $superGlobalArrays; - $blacklist[] = 'GLOBALS'; - $blacklist[] = '_PEAR_Config_instance'; - - foreach (array_keys($GLOBALS) as $key) { - if (!in_array($key, $blacklist) && !$GLOBALS[$key] instanceof Closure) { - $result .= sprintf( - '$GLOBALS[\'%s\'] = %s;' . "\n", - $key, - self::exportVariable($GLOBALS[$key]) - ); - } - } - - return $result; - } - - protected static function getSuperGlobalArrays() - { - if (ini_get('register_long_arrays') == '1') { - return array_merge( - self::$superGlobalArrays, self::$superGlobalArraysLong - ); - } else { - return self::$superGlobalArrays; - } - } - - public static function backupStaticAttributes(array $blacklist) - { - self::$staticAttributes = array(); - $declaredClasses = get_declared_classes(); - $declaredClassesNum = count($declaredClasses); - - for ($i = $declaredClassesNum - 1; $i >= 0; $i--) { - if (strpos($declaredClasses[$i], 'PHPUnit') !== 0 && - strpos($declaredClasses[$i], 'File_Iterator') !== 0 && - strpos($declaredClasses[$i], 'PHP_CodeCoverage') !== 0 && - strpos($declaredClasses[$i], 'PHP_Invoker') !== 0 && - strpos($declaredClasses[$i], 'PHP_Timer') !== 0 && - strpos($declaredClasses[$i], 'PHP_TokenStream') !== 0 && - strpos($declaredClasses[$i], 'Symfony') !== 0 && - strpos($declaredClasses[$i], 'Text_Template') !== 0 && - !$declaredClasses[$i] instanceof PHPUnit_Framework_Test) { - $class = new ReflectionClass($declaredClasses[$i]); - - if (!$class->isUserDefined()) { - break; - } - - $backup = array(); - - foreach ($class->getProperties() as $attribute) { - if ($attribute->isStatic()) { - $name = $attribute->getName(); - - if (!isset($blacklist[$declaredClasses[$i]]) || - !in_array($name, $blacklist[$declaredClasses[$i]])) { - $attribute->setAccessible(TRUE); - $value = $attribute->getValue(); - - if (!$value instanceof Closure) { - $backup[$name] = serialize($value); - } - } - } - } - - if (!empty($backup)) { - self::$staticAttributes[$declaredClasses[$i]] = $backup; - } - } - } - } - - public static function restoreStaticAttributes() - { - foreach (self::$staticAttributes as $className => $staticAttributes) { - foreach ($staticAttributes as $name => $value) { - $reflector = new ReflectionProperty($className, $name); - $reflector->setAccessible(TRUE); - $reflector->setValue(unserialize($value)); - } - } - - self::$staticAttributes = array(); - } - - protected static function exportVariable($variable) - { - if (is_scalar($variable) || is_null($variable) || - (is_array($variable) && self::arrayOnlyContainsScalars($variable))) { - return var_export($variable, TRUE); - } - - return 'unserialize(\'' . - str_replace("'", "\'", serialize($variable)) . - '\')'; - } - - protected static function arrayOnlyContainsScalars(array $array) - { - $result = TRUE; - - foreach ($array as $element) { - if (is_array($element)) { - $result = self::arrayOnlyContainsScalars($element); - } - - else if (!is_scalar($element) && !is_null($element)) { - $result = FALSE; - } - - if ($result === FALSE) { - break; - } - } - - return $result; - } - - /** - * @return array - * @since Method available since Release 3.6.0 - */ - public static function phpunitFiles() - { - if (self::$phpunitFiles === NULL) { - self::addDirectoryContainingClassToPHPUnitFilesList('File_Iterator'); - self::addDirectoryContainingClassToPHPUnitFilesList('PHP_CodeCoverage'); - self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Invoker'); - self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Timer'); - self::addDirectoryContainingClassToPHPUnitFilesList('PHP_Token'); - self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Framework_TestCase', 2); - self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_Database_TestCase', 2); - self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Framework_MockObject_Generator', 2); - self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_SeleniumTestCase', 2); - self::addDirectoryContainingClassToPHPUnitFilesList('PHPUnit_Extensions_Story_TestCase', 2); - self::addDirectoryContainingClassToPHPUnitFilesList('Text_Template'); - self::addDirectoryContainingClassToPHPUnitFilesList('SebastianBergmann\Diff'); - self::addDirectoryContainingClassToPHPUnitFilesList('SebastianBergmann\Exporter\Exporter'); - self::addDirectoryContainingClassToPHPUnitFilesList('SebastianBergmann\Version'); - } - - return self::$phpunitFiles; - } - - /** - * @param string $className - * @param integer $parent - * @since Method available since Release 3.7.2 - */ - protected static function addDirectoryContainingClassToPHPUnitFilesList($className, $parent = 1) - { - if (!class_exists($className)) { - return; - } - - $reflector = new ReflectionClass($className); - $directory = $reflector->getFileName(); - - for ($i = 0; $i < $parent; $i++) { - $directory = dirname($directory); - } - - $facade = new File_Iterator_Facade; - - foreach ($facade->getFilesAsArray($directory, '.php') as $file) { - self::$phpunitFiles[$file] = TRUE; - } - } -} diff --git a/PHPUnit/Util/InvalidArgumentHelper.php b/PHPUnit/Util/InvalidArgumentHelper.php deleted file mode 100644 index bd24eb5cfd3..00000000000 --- a/PHPUnit/Util/InvalidArgumentHelper.php +++ /dev/null @@ -1,80 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Factory for PHPUnit_Framework_Exception objects that are used to describe - * invalid arguments passed to a function or method. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -class PHPUnit_Util_InvalidArgumentHelper -{ - /** - * @param integer $argument - * @param string $type - * @param mixed $value - */ - public static function factory($argument, $type, $value = NULL) - { - $stack = debug_backtrace(FALSE); - - return new PHPUnit_Framework_Exception( - sprintf( - 'Argument #%d%sof %s::%s() must be a %s', - $argument, - $value !== NULL ? ' (' . gettype($value) . '#' . $value . ')' : ' (No Value) ', - $stack[1]['class'], - $stack[1]['function'], - $type - ) - ); - } -} diff --git a/PHPUnit/Util/Log/JSON.php b/PHPUnit/Util/Log/JSON.php deleted file mode 100644 index dbe1b812201..00000000000 --- a/PHPUnit/Util/Log/JSON.php +++ /dev/null @@ -1,250 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * A TestListener that generates JSON messages. - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Log_JSON extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener -{ - /** - * @var string - */ - protected $currentTestSuiteName = ''; - - /** - * @var string - */ - protected $currentTestName = ''; - - /** - * @var boolean - * @access private - */ - protected $currentTestPass = TRUE; - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->writeCase( - 'error', - $time, - PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE), - $e->getMessage(), - $test - ); - - $this->currentTestPass = FALSE; - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - $this->writeCase( - 'fail', - $time, - PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE), - $e->getMessage(), - $test - ); - - $this->currentTestPass = FALSE; - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->writeCase( - 'error', - $time, - PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE), - 'Incomplete Test: ' . $e->getMessage(), - $test - ); - - $this->currentTestPass = FALSE; - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->writeCase( - 'error', - $time, - PHPUnit_Util_Filter::getFilteredStacktrace($e, FALSE), - 'Skipped Test: ' . $e->getMessage(), - $test - ); - - $this->currentTestPass = FALSE; - } - - /** - * A testsuite started. - * - * @param PHPUnit_Framework_TestSuite $suite - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $this->currentTestSuiteName = $suite->getName(); - $this->currentTestName = ''; - - $this->write( - array( - 'event' => 'suiteStart', - 'suite' => $this->currentTestSuiteName, - 'tests' => count($suite) - ) - ); - } - - /** - * A testsuite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $this->currentTestSuiteName = ''; - $this->currentTestName = ''; - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - $this->currentTestName = PHPUnit_Util_Test::describe($test); - $this->currentTestPass = TRUE; - - $this->write( - array( - 'event' => 'testStart', - 'suite' => $this->currentTestSuiteName, - 'test' => $this->currentTestName - ) - ); - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if ($this->currentTestPass) { - $this->writeCase('pass', $time, array(), '', $test); - } - } - - /** - * @param string $status - * @param float $time - * @param array $trace - * @param string $message - */ - protected function writeCase($status, $time, array $trace = array(), $message = '', $test = NULL) - { - $output = ''; - if ($test !== NULL && $test->hasOutput()) { - $output = $test->getActualOutput(); - } - $this->write( - array( - 'event' => 'test', - 'suite' => $this->currentTestSuiteName, - 'test' => $this->currentTestName, - 'status' => $status, - 'time' => $time, - 'trace' => $trace, - 'message' => PHPUnit_Util_String::convertToUtf8($message), - 'output' => $output, - ) - ); - } - - /** - * @param string $buffer - */ - public function write($buffer) - { - parent::write(json_encode($buffer, JSON_PRETTY_PRINT)); - } -} diff --git a/PHPUnit/Util/Log/JUnit.php b/PHPUnit/Util/Log/JUnit.php deleted file mode 100644 index 181b3d4ad8c..00000000000 --- a/PHPUnit/Util/Log/JUnit.php +++ /dev/null @@ -1,448 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * A TestListener that generates a logfile of the test execution in XML markup. - * - * The XML markup used is the same as the one that is used by the JUnit Ant task. - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -class PHPUnit_Util_Log_JUnit extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener -{ - /** - * @var DOMDocument - */ - protected $document; - - /** - * @var DOMElement - */ - protected $root; - - /** - * @var boolean - */ - protected $logIncompleteSkipped = FALSE; - - /** - * @var boolean - */ - protected $writeDocument = TRUE; - - /** - * @var DOMElement[] - */ - protected $testSuites = array(); - - /** - * @var integer[] - */ - protected $testSuiteTests = array(0); - - /** - * @var integer[] - */ - protected $testSuiteAssertions = array(0); - - /** - * @var integer[] - */ - protected $testSuiteErrors = array(0); - - /** - * @var integer[] - */ - protected $testSuiteFailures = array(0); - - /** - * @var integer[] - */ - protected $testSuiteTimes = array(0); - - /** - * @var integer - */ - protected $testSuiteLevel = 0; - - /** - * @var DOMElement - */ - protected $currentTestCase = NULL; - - /** - * @var boolean - */ - protected $attachCurrentTestCase = TRUE; - - /** - * Constructor. - * - * @param mixed $out - * @param boolean $logIncompleteSkipped - */ - public function __construct($out = NULL, $logIncompleteSkipped = FALSE) - { - $this->document = new DOMDocument('1.0', 'UTF-8'); - $this->document->formatOutput = TRUE; - - $this->root = $this->document->createElement('testsuites'); - $this->document->appendChild($this->root); - - parent::__construct($out); - - $this->logIncompleteSkipped = $logIncompleteSkipped; - } - - /** - * Flush buffer and close output. - * - */ - public function flush() - { - if ($this->writeDocument === TRUE) { - $this->write($this->getXML()); - } - - parent::flush(); - } - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->currentTestCase !== NULL) { - if ($test instanceof PHPUnit_Framework_SelfDescribing) { - $buffer = $test->toString() . "\n"; - } else { - $buffer = ''; - } - - $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) . - "\n" . - PHPUnit_Util_Filter::getFilteredStacktrace($e); - - $error = $this->document->createElement( - 'error', PHPUnit_Util_XML::prepareString($buffer) - ); - - $error->setAttribute('type', get_class($e)); - - $this->currentTestCase->appendChild($error); - - $this->testSuiteErrors[$this->testSuiteLevel]++; - } - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - if ($this->currentTestCase !== NULL) { - if (!$test instanceof PHPUnit_Framework_Warning) { - if ($test instanceof PHPUnit_Framework_SelfDescribing) { - $buffer = $test->toString() . "\n"; - } else { - $buffer = ''; - } - - $buffer .= PHPUnit_Framework_TestFailure::exceptionToString($e) . - "\n" . - PHPUnit_Util_Filter::getFilteredStacktrace($e); - - $failure = $this->document->createElement( - 'failure', PHPUnit_Util_XML::prepareString($buffer) - ); - - $failure->setAttribute('type', get_class($e)); - - $this->currentTestCase->appendChild($failure); - - $this->testSuiteFailures[$this->testSuiteLevel]++; - } - } - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) { - $error = $this->document->createElement( - 'error', - PHPUnit_Util_XML::prepareString( - "Incomplete Test\n" . - PHPUnit_Util_Filter::getFilteredStacktrace($e) - ) - ); - - $error->setAttribute('type', get_class($e)); - - $this->currentTestCase->appendChild($error); - - $this->testSuiteErrors[$this->testSuiteLevel]++; - } else { - $this->attachCurrentTestCase = FALSE; - } - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($this->logIncompleteSkipped && $this->currentTestCase !== NULL) { - $error = $this->document->createElement( - 'error', - PHPUnit_Util_XML::prepareString( - "Skipped Test\n" . - PHPUnit_Util_Filter::getFilteredStacktrace($e) - ) - ); - - $error->setAttribute('type', get_class($e)); - - $this->currentTestCase->appendChild($error); - - $this->testSuiteErrors[$this->testSuiteLevel]++; - } else { - $this->attachCurrentTestCase = FALSE; - } - } - - /** - * A testsuite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $testSuite = $this->document->createElement('testsuite'); - $testSuite->setAttribute('name', $suite->getName()); - - if (class_exists($suite->getName(), FALSE)) { - try { - $class = new ReflectionClass($suite->getName()); - - $testSuite->setAttribute('file', $class->getFileName()); - } - - catch (ReflectionException $e) { - } - } - - if ($this->testSuiteLevel > 0) { - $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); - } else { - $this->root->appendChild($testSuite); - } - - $this->testSuiteLevel++; - $this->testSuites[$this->testSuiteLevel] = $testSuite; - $this->testSuiteTests[$this->testSuiteLevel] = 0; - $this->testSuiteAssertions[$this->testSuiteLevel] = 0; - $this->testSuiteErrors[$this->testSuiteLevel] = 0; - $this->testSuiteFailures[$this->testSuiteLevel] = 0; - $this->testSuiteTimes[$this->testSuiteLevel] = 0; - } - - /** - * A testsuite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $this->testSuites[$this->testSuiteLevel]->setAttribute( - 'tests', $this->testSuiteTests[$this->testSuiteLevel] - ); - - $this->testSuites[$this->testSuiteLevel]->setAttribute( - 'assertions', $this->testSuiteAssertions[$this->testSuiteLevel] - ); - - $this->testSuites[$this->testSuiteLevel]->setAttribute( - 'failures', $this->testSuiteFailures[$this->testSuiteLevel] - ); - - $this->testSuites[$this->testSuiteLevel]->setAttribute( - 'errors', $this->testSuiteErrors[$this->testSuiteLevel] - ); - - $this->testSuites[$this->testSuiteLevel]->setAttribute( - 'time', sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel]) - ); - - if ($this->testSuiteLevel > 1) { - $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; - $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; - $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; - $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; - $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; - } - - $this->testSuiteLevel--; - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - if (!$test instanceof PHPUnit_Framework_Warning) { - $testCase = $this->document->createElement('testcase'); - $testCase->setAttribute('name', $test->getName()); - - if ($test instanceof PHPUnit_Framework_TestCase) { - $class = new ReflectionClass($test); - $methodName = $test->getName(); - - if ($class->hasMethod($methodName)) { - $method = $class->getMethod($test->getName()); - - $testCase->setAttribute('class', $class->getName()); - $testCase->setAttribute('file', $class->getFileName()); - $testCase->setAttribute('line', $method->getStartLine()); - } - } - - $this->currentTestCase = $testCase; - } - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if (!$test instanceof PHPUnit_Framework_Warning) { - if ($this->attachCurrentTestCase) { - if ($test instanceof PHPUnit_Framework_TestCase) { - $numAssertions = $test->getNumAssertions(); - $this->testSuiteAssertions[$this->testSuiteLevel] += $numAssertions; - - $this->currentTestCase->setAttribute( - 'assertions', $numAssertions - ); - } - - $this->currentTestCase->setAttribute( - 'time', sprintf('%F', $time) - ); - - $this->testSuites[$this->testSuiteLevel]->appendChild( - $this->currentTestCase - ); - - $this->testSuiteTests[$this->testSuiteLevel]++; - $this->testSuiteTimes[$this->testSuiteLevel] += $time; - } - } - - $this->attachCurrentTestCase = TRUE; - $this->currentTestCase = NULL; - } - - /** - * Returns the XML as a string. - * - * @return string - * @since Method available since Release 2.2.0 - */ - public function getXML() - { - return $this->document->saveXML(); - } - - /** - * Enables or disables the writing of the document - * in flush(). - * - * This is a "hack" needed for the integration of - * PHPUnit with Phing. - * - * @return string - * @since Method available since Release 2.2.0 - */ - public function setWriteDocument($flag) - { - if (is_bool($flag)) { - $this->writeDocument = $flag; - } - } -} diff --git a/PHPUnit/Util/Log/TAP.php b/PHPUnit/Util/Log/TAP.php deleted file mode 100644 index b2050cda535..00000000000 --- a/PHPUnit/Util/Log/TAP.php +++ /dev/null @@ -1,250 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * A TestListener that generates a logfile of the - * test execution using the Test Anything Protocol (TAP). - * - * @package PHPUnit - * @subpackage Util_Log - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Log_TAP extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener -{ - /** - * @var integer - */ - protected $testNumber = 0; - - /** - * @var integer - */ - protected $testSuiteLevel = 0; - - /** - * @var boolean - */ - protected $testSuccessful = TRUE; - - /** - * Constructor. - * - * @param mixed $out - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.3.4 - */ - public function __construct($out = NULL) - { - parent::__construct($out); - $this->write("TAP version 13\n"); - } - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->writeNotOk($test, 'Error'); - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - $this->writeNotOk($test, 'Failure'); - - $message = explode( - "\n", PHPUnit_Framework_TestFailure::exceptionToString($e) - ); - - $diagnostic = array( - 'message' => $message[0], - 'severity' => 'fail' - ); - - if ($e instanceof PHPUnit_Framework_ExpectationFailedException) { - $cf = $e->getComparisonFailure(); - - if ($cf !== NULL) { - $diagnostic['data'] = array( - 'got' => $cf->getActual(), - 'expected' => $cf->getExpected() - ); - } - } - - $yaml = new Symfony\Component\Yaml\Dumper; - - $this->write( - sprintf( - " ---\n%s ...\n", - $yaml->dump($diagnostic, 2, 2) - ) - ); - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->writeNotOk($test, '', 'TODO Incomplete Test'); - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->write( - sprintf( - "ok %d - # SKIP%s\n", - - $this->testNumber, - $e->getMessage() != '' ? ' ' . $e->getMessage() : '' - ) - ); - - $this->testSuccessful = FALSE; - } - - /** - * A testsuite started. - * - * @param PHPUnit_Framework_TestSuite $suite - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $this->testSuiteLevel++; - } - - /** - * A testsuite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - $this->testSuiteLevel--; - - if ($this->testSuiteLevel == 0) { - $this->write(sprintf("1..%d\n", $this->testNumber)); - } - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - $this->testNumber++; - $this->testSuccessful = TRUE; - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if ($this->testSuccessful === TRUE) { - $this->write( - sprintf( - "ok %d - %s\n", - - $this->testNumber, - PHPUnit_Util_Test::describe($test) - ) - ); - } - } - - /** - * @param PHPUnit_Framework_Test $test - * @param string $prefix - * @param string $directive - */ - protected function writeNotOk(PHPUnit_Framework_Test $test, $prefix = '', $directive = '') - { - $this->write( - sprintf( - "not ok %d - %s%s%s\n", - - $this->testNumber, - $prefix != '' ? $prefix . ': ' : '', - PHPUnit_Util_Test::describe($test), - $directive != '' ? ' # ' . $directive : '' - ) - ); - - $this->testSuccessful = FALSE; - } -} diff --git a/PHPUnit/Util/PHP.php b/PHPUnit/Util/PHP.php deleted file mode 100644 index cdf0b80f4f2..00000000000 --- a/PHPUnit/Util/PHP.php +++ /dev/null @@ -1,254 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.4.0 - */ - -/** - * Utility methods for PHP sub-processes. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.4.0 - */ -abstract class PHPUnit_Util_PHP -{ - /** - * @return PHPUnit_Util_PHP - * @since Method available since Release 3.5.12 - */ - public static function factory() - { - if (DIRECTORY_SEPARATOR == '\\') { - return new PHPUnit_Util_PHP_Windows; - } - - return new PHPUnit_Util_PHP_Default; - } - - /** - * Runs a single job (PHP code) using a separate PHP process. - * - * @param string $job - * @param PHPUnit_Framework_TestCase $test - * @param PHPUnit_Framework_TestResult $result - * @return array|null - * @throws PHPUnit_Framework_Exception - */ - public function runJob($job, PHPUnit_Framework_Test $test = NULL, PHPUnit_Framework_TestResult $result = NULL) - { - $process = proc_open( - escapeshellarg(PHP_BINARY), - array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w') - ), - $pipes - ); - - if (!is_resource($process)) { - throw new PHPUnit_Framework_Exception( - 'Unable to create process for process isolation.' - ); - } - - if ($result !== NULL) { - $result->startTest($test); - } - - $this->process($pipes[0], $job); - fclose($pipes[0]); - - $stdout = stream_get_contents($pipes[1]); - fclose($pipes[1]); - - $stderr = stream_get_contents($pipes[2]); - fclose($pipes[2]); - - proc_close($process); - $this->cleanup(); - - if ($result !== NULL) { - $this->processChildResult($test, $result, $stdout, $stderr); - } else { - return array('stdout' => $stdout, 'stderr' => $stderr); - } - } - - /** - * @param resource $pipe - * @param string $job - * @since Method available since Release 3.5.12 - */ - abstract protected function process($pipe, $job); - - /** - * @since Method available since Release 3.5.12 - */ - protected function cleanup() - { - } - - /** - * Processes the TestResult object from an isolated process. - * - * @param PHPUnit_Framework_TestCase $test - * @param PHPUnit_Framework_TestResult $result - * @param string $stdout - * @param string $stderr - * @since Method available since Release 3.5.0 - */ - protected function processChildResult(PHPUnit_Framework_Test $test, PHPUnit_Framework_TestResult $result, $stdout, $stderr) - { - $time = 0; - - if (!empty($stderr)) { - $result->addError( - $test, - new PHPUnit_Framework_Exception(trim($stderr)), $time - ); - } else { - set_error_handler(function($errno, $errstr, $errfile, $errline) { - throw new ErrorException($errstr, $errno, $errno, $errfile, $errline); - }); - try { - $childResult = unserialize($stdout); - restore_error_handler(); - } catch (ErrorException $e) { - restore_error_handler(); - $childResult = FALSE; - - $result->addError( - $test, new PHPUnit_Framework_Exception(trim($stdout), 0, $e), $time - ); - } - - if ($childResult !== FALSE) { - if (!empty($childResult['output'])) { - print $childResult['output']; - } - - $test->setResult($childResult['testResult']); - $test->addToAssertionCount($childResult['numAssertions']); - - $childResult = $childResult['result']; - - if ($result->getCollectCodeCoverageInformation()) { - $result->getCodeCoverage()->merge( - $childResult->getCodeCoverage() - ); - } - - $time = $childResult->time(); - $notImplemented = $childResult->notImplemented(); - $skipped = $childResult->skipped(); - $errors = $childResult->errors(); - $failures = $childResult->failures(); - - if (!empty($notImplemented)) { - $result->addError( - $test, $this->getException($notImplemented[0]), $time - ); - } - - else if (!empty($skipped)) { - $result->addError( - $test, $this->getException($skipped[0]), $time - ); - } - - else if (!empty($errors)) { - $result->addError( - $test, $this->getException($errors[0]), $time - ); - } - - else if (!empty($failures)) { - $result->addFailure( - $test, $this->getException($failures[0]), $time - ); - } - } - } - - $result->endTest($test, $time); - } - - /** - * Gets the thrown exception from a PHPUnit_Framework_TestFailure. - * - * @param PHPUnit_Framework_TestFailure $error - * @since Method available since Release 3.6.0 - * @see https://github.com/sebastianbergmann/phpunit/issues/74 - */ - protected function getException(PHPUnit_Framework_TestFailure $error) - { - $exception = $error->thrownException(); - - if ($exception instanceof __PHP_Incomplete_Class) { - $exceptionArray = array(); - foreach ((array)$exception as $key => $value) { - $key = substr($key, strrpos($key, "\0") + 1); - $exceptionArray[$key] = $value; - } - - $exception = new PHPUnit_Framework_SyntheticError( - sprintf( - '%s: %s', - $exceptionArray['_PHP_Incomplete_Class_Name'], - $exceptionArray['message'] - ), - $exceptionArray['code'], - $exceptionArray['file'], - $exceptionArray['line'], - $exceptionArray['trace'] - ); - } - - return $exception; - } -} diff --git a/PHPUnit/Util/PHP/Default.php b/PHPUnit/Util/PHP/Default.php deleted file mode 100644 index c8b53a7937b..00000000000 --- a/PHPUnit/Util/PHP/Default.php +++ /dev/null @@ -1,67 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.12 - */ - -/** - * Default utility for PHP sub-processes. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.12 - */ -class PHPUnit_Util_PHP_Default extends PHPUnit_Util_PHP -{ - /** - * @param resource $pipe - * @since Method available since Release 3.5.12 - */ - protected function process($pipe, $job) - { - fwrite($pipe, $job); - } -} diff --git a/PHPUnit/Util/PHP/Windows.php b/PHPUnit/Util/PHP/Windows.php deleted file mode 100644 index 058f10d25f6..00000000000 --- a/PHPUnit/Util/PHP/Windows.php +++ /dev/null @@ -1,90 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.5.12 - */ - -/** - * Windows utility for PHP sub-processes. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.5.12 - */ -class PHPUnit_Util_PHP_Windows extends PHPUnit_Util_PHP -{ - /** - * @var string - */ - protected $tempFile; - - /** - * @param resource $pipe - * @since Method available since Release 3.5.12 - */ - protected function process($pipe, $job) - { - if (!($this->tempFile = tempnam(sys_get_temp_dir(), 'PHPUnit')) || - file_put_contents($this->tempFile, $job) === FALSE) { - throw new PHPUnit_Framework_Exception( - 'Unable to write temporary files for process isolation.' - ); - } - - fwrite( - $pipe, - "tempFile, TRUE) . "; ?>" - ); - } - - /** - * @since Method available since Release 3.5.12 - */ - protected function cleanup() - { - unlink($this->tempFile); - } -} diff --git a/PHPUnit/Util/Printer.php b/PHPUnit/Util/Printer.php deleted file mode 100644 index ec66afb9293..00000000000 --- a/PHPUnit/Util/Printer.php +++ /dev/null @@ -1,208 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -/** - * Utility class that can print to STDOUT or write to a file. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class PHPUnit_Util_Printer -{ - /** - * If TRUE, flush output after every write. - * - * @var boolean - */ - protected $autoFlush = FALSE; - - /** - * @var resource - */ - protected $out; - - /** - * @var string - */ - protected $outTarget; - - /** - * @var boolean - */ - protected $printsHTML = FALSE; - - /** - * Constructor. - * - * @param mixed $out - * @throws PHPUnit_Framework_Exception - */ - public function __construct($out = NULL) - { - if ($out !== NULL) { - if (is_string($out)) { - if (strpos($out, 'socket://') === 0) { - $out = explode(':', str_replace('socket://', '', $out)); - - if (sizeof($out) != 2) { - throw new PHPUnit_Framework_Exception; - } - - $this->out = fsockopen($out[0], $out[1]); - } else { - if (strpos($out, 'php://') === FALSE && - !is_dir(dirname($out))) { - mkdir(dirname($out), 0777, TRUE); - } - - $this->out = fopen($out, 'wt'); - } - - $this->outTarget = $out; - } else { - $this->out = $out; - } - } - } - - /** - * Flush buffer, optionally tidy up HTML, and close output if it's not to a php stream - */ - public function flush() - { - if ($this->out && strncmp($this->outTarget, 'php://', 6) !== 0) { - fclose($this->out); - } - - if ($this->printsHTML === TRUE && - $this->outTarget !== NULL && - strpos($this->outTarget, 'php://') !== 0 && - strpos($this->outTarget, 'socket://') !== 0 && - extension_loaded('tidy')) { - file_put_contents( - $this->outTarget, - tidy_repair_file( - $this->outTarget, array('indent' => TRUE, 'wrap' => 0), 'utf8' - ) - ); - } - } - - /** - * Performs a safe, incremental flush. - * - * Do not confuse this function with the flush() function of this class, - * since the flush() function may close the file being written to, rendering - * the current object no longer usable. - * - * @since Method available since Release 3.3.0 - */ - public function incrementalFlush() - { - if ($this->out) { - fflush($this->out); - } else { - flush(); - } - } - - /** - * @param string $buffer - */ - public function write($buffer) - { - if ($this->out) { - fwrite($this->out, $buffer); - - if ($this->autoFlush) { - $this->incrementalFlush(); - } - } else { - if (PHP_SAPI != 'cli') { - $buffer = htmlspecialchars($buffer); - } - - print $buffer; - - if ($this->autoFlush) { - $this->incrementalFlush(); - } - } - } - - /** - * Check auto-flush mode. - * - * @return boolean - * @since Method available since Release 3.3.0 - */ - public function getAutoFlush() - { - return $this->autoFlush; - } - - /** - * Set auto-flushing mode. - * - * If set, *incremental* flushes will be done after each write. This should - * not be confused with the different effects of this class' flush() method. - * - * @param boolean $autoFlush - * @since Method available since Release 3.3.0 - */ - public function setAutoFlush($autoFlush) - { - if (is_bool($autoFlush)) { - $this->autoFlush = $autoFlush; - } else { - throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'boolean'); - } - } -} diff --git a/PHPUnit/Util/String.php b/PHPUnit/Util/String.php deleted file mode 100644 index 38d934aaf67..00000000000 --- a/PHPUnit/Util/String.php +++ /dev/null @@ -1,118 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * String helpers. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class PHPUnit_Util_String -{ - /** - * Converts a string to UTF-8 encoding. - * - * @param string $string - * @return string - */ - public static function convertToUtf8($string) - { - if (!self::isUtf8($string)) { - if (function_exists('mb_convert_encoding')) { - $string = mb_convert_encoding($string, 'UTF-8'); - } else { - $string = utf8_encode($string); - } - } - - return $string; - } - - /** - * Checks a string for UTF-8 encoding. - * - * @param string $string - * @return boolean - */ - protected static function isUtf8($string) - { - $length = strlen($string); - - for ($i = 0; $i < $length; $i++) { - if (ord($string[$i]) < 0x80) { - $n = 0; - } - - else if ((ord($string[$i]) & 0xE0) == 0xC0) { - $n = 1; - } - - else if ((ord($string[$i]) & 0xF0) == 0xE0) { - $n = 2; - } - - else if ((ord($string[$i]) & 0xF0) == 0xF0) { - $n = 3; - } - - else { - return FALSE; - } - - for ($j = 0; $j < $n; $j++) { - if ((++$i == $length) || ((ord($string[$i]) & 0xC0) != 0x80)) { - return FALSE; - } - } - } - - return TRUE; - } -} diff --git a/PHPUnit/Util/Test.php b/PHPUnit/Util/Test.php deleted file mode 100644 index 70a0dbe2c82..00000000000 --- a/PHPUnit/Util/Test.php +++ /dev/null @@ -1,608 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Test helpers. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Test -{ - const REGEX_DATA_PROVIDER = '/@dataProvider\s+([a-zA-Z0-9._:-\\\\x7f-\xff]+)/'; - const REGEX_EXPECTED_EXCEPTION = '(@expectedException\s+([:.\w\\\\x7f-\xff]+)(?:[\t ]+(\S*))?(?:[\t ]+(\S*))?\s*$)m'; - const REGEX_REQUIRES_VERSION = '/@requires\s+(?PPHP(?:Unit)?)\s+(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m'; - const REGEX_REQUIRES_OS = '/@requires\s+OS\s+(?P.+)\r?$/m'; - const REGEX_REQUIRES = '/@requires\s+(?Pfunction|extension)\s(?P([^ ]+))\r?$/m'; - - const SMALL = 0; - const MEDIUM = 1; - const LARGE = 2; - - private static $annotationCache = array(); - - protected static $templateMethods = array( - 'setUp', 'assertPreConditions', 'assertPostConditions', 'tearDown' - ); - - /** - * @param PHPUnit_Framework_Test $test - * @param boolean $asString - * @return mixed - */ - public static function describe(PHPUnit_Framework_Test $test, $asString = TRUE) - { - if ($asString) { - if ($test instanceof PHPUnit_Framework_SelfDescribing) { - return $test->toString(); - } else { - return get_class($test); - } - } else { - if ($test instanceof PHPUnit_Framework_TestCase) { - return array( - get_class($test), $test->getName() - ); - } - - else if ($test instanceof PHPUnit_Framework_SelfDescribing) { - return array('', $test->toString()); - } - - else { - return array('', get_class($test)); - } - } - } - - /** - * Returns the requirements for a test. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.6.0 - */ - public static function getRequirements($className, $methodName) - { - $reflector = new ReflectionClass($className); - $docComment = $reflector->getDocComment(); - $reflector = new ReflectionMethod($className, $methodName); - $docComment .= "\n" . $reflector->getDocComment(); - $requires = array(); - - if ($count = preg_match_all(self::REGEX_REQUIRES_OS, $docComment, $matches)) { - $requires['OS'] = sprintf( - '/%s/i', - addcslashes($matches['value'][$count - 1], '/') - ); - } - if ($count = preg_match_all(self::REGEX_REQUIRES_VERSION, $docComment, $matches)) { - for ($i = 0; $i < $count; $i++) { - $requires[$matches['name'][$i]] = $matches['value'][$i]; - } - } - if ($count = preg_match_all(self::REGEX_REQUIRES, $docComment, $matches)) { - for ($i = 0; $i < $count; $i++) { - $name = $matches['name'][$i] . 's'; - if (!isset($requires[$name])) { - $requires[$name] = array(); - } - $requires[$name][] = $matches['value'][$i]; - } - } - - return $requires; - } - - /** - * Returns the expected exception for a test. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.3.6 - */ - public static function getExpectedException($className, $methodName) - { - $reflector = new ReflectionMethod($className, $methodName); - $docComment = $reflector->getDocComment(); - - if (preg_match(self::REGEX_EXPECTED_EXCEPTION, $docComment, $matches)) { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - $class = $matches[1]; - $code = NULL; - $message = ''; - - if (isset($matches[2])) { - $message = trim($matches[2]); - } - - else if (isset($annotations['method']['expectedExceptionMessage'])) { - $message = self::_parseAnnotationContent( - $annotations['method']['expectedExceptionMessage'][0] - ); - } - - if (isset($matches[3])) { - $code = $matches[3]; - } - - else if (isset($annotations['method']['expectedExceptionCode'])) { - $code = self::_parseAnnotationContent( - $annotations['method']['expectedExceptionCode'][0] - ); - } - - if (is_numeric($code)) { - $code = (int)$code; - } - - else if (is_string($code) && defined($code)) { - $code = (int)constant($code); - } - - return array( - 'class' => $class, 'code' => $code, 'message' => $message - ); - } - - return FALSE; - } - - /** - * Parse annotation content to use constant/class constant values - * - * Constants are specified using a starting '@'. For example: @ClassName::CONST_NAME - * - * If the constant is not found the string is used as is to ensure maximum BC. - * - * @param string $message - * @return string - */ - protected static function _parseAnnotationContent($message) - { - if (strpos($message, '::') !== FALSE && count(explode('::', $message) == 2)) { - if (defined($message)) { - $message = constant($message); - } - } - return $message; - } - - /** - * Returns the provided data for a method. - * - * @param string $className - * @param string $methodName - * @param string $docComment - * @return mixed array|Iterator when a data provider is specified and exists - * false when a data provider is specified and does not exist - * null when no data provider is specified - * @since Method available since Release 3.2.0 - */ - public static function getProvidedData($className, $methodName) - { - $reflector = new ReflectionMethod($className, $methodName); - $docComment = $reflector->getDocComment(); - $data = NULL; - - if (preg_match(self::REGEX_DATA_PROVIDER, $docComment, $matches)) { - $dataProviderMethodNameNamespace = explode('\\', $matches[1]); - $leaf = explode('::', array_pop($dataProviderMethodNameNamespace)); - $dataProviderMethodName = array_pop($leaf); - - if (!empty($dataProviderMethodNameNamespace)) { - $dataProviderMethodNameNamespace = join('\\', $dataProviderMethodNameNamespace) . '\\'; - } else { - $dataProviderMethodNameNamespace = ''; - } - - if (!empty($leaf)) { - $dataProviderClassName = $dataProviderMethodNameNamespace . array_pop($leaf); - } else { - $dataProviderClassName = $className; - } - - $dataProviderClass = new ReflectionClass($dataProviderClassName); - $dataProviderMethod = $dataProviderClass->getMethod( - $dataProviderMethodName - ); - - if ($dataProviderMethod->isStatic()) { - $object = NULL; - } else { - $object = $dataProviderClass->newInstance(); - } - - if ($dataProviderMethod->getNumberOfParameters() == 0) { - $data = $dataProviderMethod->invoke($object); - } else { - $data = $dataProviderMethod->invoke($object, $methodName); - } - } - - if ($data !== NULL) { - foreach ($data as $key => $value) { - if (!is_array($value)) { - throw new PHPUnit_Framework_Exception( - sprintf( - 'Data set %s is invalid.', - is_int($key) ? '#' . $key : '"' . $key . '"' - ) - ); - } - } - } - - return $data; - } - - /** - * @param string $className - * @param string $methodName - * @return array - * @throws ReflectionException - * @since Method available since Release 3.4.0 - */ - public static function parseTestMethodAnnotations($className, $methodName = '') - { - if (!isset(self::$annotationCache[$className])) { - $class = new ReflectionClass($className); - self::$annotationCache[$className] = self::parseAnnotations($class->getDocComment()); - } - - if (!empty($methodName) && !isset(self::$annotationCache[$className . '::' . $methodName])) { - try { - $method = new ReflectionMethod($className, $methodName); - $annotations = self::parseAnnotations($method->getDocComment()); - } catch (ReflectionException $e) { - $annotations = array(); - } - self::$annotationCache[$className . '::' . $methodName] = $annotations; - } - - return array( - 'class' => self::$annotationCache[$className], - 'method' => !empty($methodName) ? self::$annotationCache[$className . '::' . $methodName] : array() - ); - } - - /** - * @param string $docblock - * @return array - * @since Method available since Release 3.4.0 - */ - private static function parseAnnotations($docblock) - { - $annotations = array(); - // Strip away the docblock header and footer to ease parsing of one line annotations - $docblock = substr($docblock, 3, -2); - - if (preg_match_all('/@(?P[A-Za-z_-]+)(?:[ \t]+(?P.*?))?[ \t]*\r?$/m', $docblock, $matches)) { - $numMatches = count($matches[0]); - - for ($i = 0; $i < $numMatches; ++$i) { - $annotations[$matches['name'][$i]][] = $matches['value'][$i]; - } - } - - return $annotations; - } - - /** - * Returns the backup settings for a test. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.4.0 - */ - public static function getBackupSettings($className, $methodName) - { - return array( - 'backupGlobals' => self::getBooleanAnnotationSetting( - $className, $methodName, 'backupGlobals' - ), - 'backupStaticAttributes' => self::getBooleanAnnotationSetting( - $className, $methodName, 'backupStaticAttributes' - ) - ); - } - - /** - * Returns the dependencies for a test class or method. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.4.0 - */ - public static function getDependencies($className, $methodName) - { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - $dependencies = array(); - - if (isset($annotations['class']['depends'])) { - $dependencies = $annotations['class']['depends']; - } - - if (isset($annotations['method']['depends'])) { - $dependencies = array_merge( - $dependencies, $annotations['method']['depends'] - ); - } - - return array_unique($dependencies); - } - - /** - * Returns the error handler settings for a test. - * - * @param string $className - * @param string $methodName - * @return boolean - * @since Method available since Release 3.4.0 - */ - public static function getErrorHandlerSettings($className, $methodName) - { - return self::getBooleanAnnotationSetting( - $className, $methodName, 'errorHandler' - ); - } - - /** - * Returns the groups for a test class or method. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.2.0 - */ - public static function getGroups($className, $methodName = '') - { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - $groups = array(); - - if (isset($annotations['method']['author'])) { - $groups = $annotations['method']['author']; - } - - else if (isset($annotations['class']['author'])) { - $groups = $annotations['class']['author']; - } - - if (isset($annotations['class']['group'])) { - $groups = array_merge($groups, $annotations['class']['group']); - } - - if (isset($annotations['method']['group'])) { - $groups = array_merge($groups, $annotations['method']['group']); - } - - if (isset($annotations['class']['ticket'])) { - $groups = array_merge($groups, $annotations['class']['ticket']); - } - - if (isset($annotations['method']['ticket'])) { - $groups = array_merge($groups, $annotations['method']['ticket']); - } - - foreach (array('small', 'medium', 'large') as $size) { - if (isset($annotations['method'][$size])) { - $groups[] = $size; - } - - else if (isset($annotations['class'][$size])) { - $groups[] = $size; - } - } - - return array_unique($groups); - } - - /** - * Returns the size of the test. - * - * @param string $className - * @param string $methodName - * @return integer - * @since Method available since Release 3.6.0 - */ - public static function getSize($className, $methodName) - { - $groups = array_flip(self::getGroups($className, $methodName)); - $size = self::SMALL; - $class = new ReflectionClass($className); - - if ((class_exists('PHPUnit_Extensions_Database_TestCase', FALSE) && - $class->isSubclassOf('PHPUnit_Extensions_Database_TestCase')) || - (class_exists('PHPUnit_Extensions_SeleniumTestCase', FALSE) && - $class->isSubclassOf('PHPUnit_Extensions_SeleniumTestCase'))) { - $size = self::LARGE; - } - - else if (isset($groups['medium'])) { - $size = self::MEDIUM; - } - - else if (isset($groups['large'])) { - $size = self::LARGE; - } - - return $size; - } - - /** - * Returns the tickets for a test class or method. - * - * @param string $className - * @param string $methodName - * @return array - * @since Method available since Release 3.4.0 - */ - public static function getTickets($className, $methodName) - { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - $tickets = array(); - - if (isset($annotations['class']['ticket'])) { - $tickets = $annotations['class']['ticket']; - } - - if (isset($annotations['method']['ticket'])) { - $tickets = array_merge($tickets, $annotations['method']['ticket']); - } - - return array_unique($tickets); - } - - /** - * Returns the output buffering settings for a test. - * - * @param string $className - * @param string $methodName - * @return boolean - * @since Method available since Release 3.4.0 - */ - public static function getOutputBufferingSettings($className, $methodName) - { - return self::getBooleanAnnotationSetting( - $className, $methodName, 'outputBuffering' - ); - } - - /** - * Returns the process isolation settings for a test. - * - * @param string $className - * @param string $methodName - * @return boolean - * @since Method available since Release 3.4.1 - */ - public static function getProcessIsolationSettings($className, $methodName) - { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - if (isset($annotations['class']['runTestsInSeparateProcesses']) || - isset($annotations['method']['runInSeparateProcess'])) { - return TRUE; - } else { - return FALSE; - } - } - - /** - * Returns the preserve global state settings for a test. - * - * @param string $className - * @param string $methodName - * @return boolean - * @since Method available since Release 3.4.0 - */ - public static function getPreserveGlobalStateSettings($className, $methodName) - { - return self::getBooleanAnnotationSetting( - $className, $methodName, 'preserveGlobalState' - ); - } - - /** - * @param string $className - * @param string $methodName - * @param string $settingName - * @return boolean - * @since Method available since Release 3.4.0 - */ - private static function getBooleanAnnotationSetting($className, $methodName, $settingName) - { - $annotations = self::parseTestMethodAnnotations( - $className, $methodName - ); - - $result = NULL; - - if (isset($annotations['class'][$settingName])) { - if ($annotations['class'][$settingName][0] == 'enabled') { - $result = TRUE; - } - - else if ($annotations['class'][$settingName][0] == 'disabled') { - $result = FALSE; - } - } - - if (isset($annotations['method'][$settingName])) { - if ($annotations['method'][$settingName][0] == 'enabled') { - $result = TRUE; - } - - else if ($annotations['method'][$settingName][0] == 'disabled') { - $result = FALSE; - } - } - - return $result; - } -} diff --git a/PHPUnit/Util/TestDox/NamePrettifier.php b/PHPUnit/Util/TestDox/NamePrettifier.php deleted file mode 100644 index 2be7934fbdc..00000000000 --- a/PHPUnit/Util/TestDox/NamePrettifier.php +++ /dev/null @@ -1,177 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * Prettifies class and method names for use in TestDox documentation. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -class PHPUnit_Util_TestDox_NamePrettifier -{ - /** - * @var string - */ - protected $prefix = 'Test'; - - /** - * @var string - */ - protected $suffix = 'Test'; - - /** - * @var array - */ - protected $strings = array(); - - /** - * Prettifies the name of a test class. - * - * @param string $name - * @return string - */ - public function prettifyTestClass($name) - { - $title = $name; - - if ($this->suffix !== NULL && - $this->suffix == substr($name, -1 * strlen($this->suffix))) { - $title = substr($title, 0, strripos($title, $this->suffix)); - } - - if ($this->prefix !== NULL && - $this->prefix == substr($name, 0, strlen($this->prefix))) { - $title = substr($title, strlen($this->prefix)); - } - - return $title; - } - - /** - * Prettifies the name of a test method. - * - * @param string $name - * @return string - */ - public function prettifyTestMethod($name) - { - $buffer = ''; - - if (!is_string($name) || strlen($name) == 0) { - return $buffer; - } - - $string = preg_replace('#\d+$#', '', $name, -1, $count); - - if (in_array($string, $this->strings)) { - $name = $string; - } else if ($count == 0) { - $this->strings[] = $string; - } - - if (strpos($name, '_') !== FALSE) { - return str_replace('_', ' ', $name); - } - - $max = strlen($name); - - if (substr($name, 0, 4) == 'test') { - $offset = 4; - } else { - $offset = 0; - $name[0] = strtoupper($name[0]); - } - - $wasNumeric = FALSE; - - for ($i = $offset; $i < $max; $i++) { - if ($i > $offset && - ord($name[$i]) >= 65 && - ord($name[$i]) <= 90) { - $buffer .= ' ' . strtolower($name[$i]); - } else { - $isNumeric = is_numeric($name[$i]); - - if (!$wasNumeric && $isNumeric) { - $buffer .= ' '; - $wasNumeric = TRUE; - } - - if ($wasNumeric && !$isNumeric) { - $wasNumeric = FALSE; - } - - $buffer .= $name[$i]; - } - } - - return $buffer; - } - - /** - * Sets the prefix of test names. - * - * @param string $prefix - */ - public function setPrefix($prefix) - { - $this->prefix = $prefix; - } - - /** - * Sets the suffix of test names. - * - * @param string $prefix - */ - public function setSuffix($suffix) - { - $this->suffix = $suffix; - } -} diff --git a/PHPUnit/Util/TestDox/ResultPrinter.php b/PHPUnit/Util/TestDox/ResultPrinter.php deleted file mode 100644 index 9e28b71e4ab..00000000000 --- a/PHPUnit/Util/TestDox/ResultPrinter.php +++ /dev/null @@ -1,347 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * Base class for printers of TestDox documentation. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -abstract class PHPUnit_Util_TestDox_ResultPrinter extends PHPUnit_Util_Printer implements PHPUnit_Framework_TestListener -{ - /** - * @var PHPUnit_Util_TestDox_NamePrettifier - */ - protected $prettifier; - - /** - * @var string - */ - protected $testClass = ''; - - /** - * @var integer - */ - protected $testStatus = FALSE; - - /** - * @var array - */ - protected $tests = array(); - - /** - * @var integer - */ - protected $successful = 0; - - /** - * @var integer - */ - protected $failed = 0; - - /** - * @var integer - */ - protected $skipped = 0; - - /** - * @var integer - */ - protected $incomplete = 0; - - /** - * @var string - */ - protected $testTypeOfInterest = 'PHPUnit_Framework_TestCase'; - - /** - * @var string - */ - protected $currentTestClassPrettified; - - /** - * @var string - */ - protected $currentTestMethodPrettified; - - /** - * Constructor. - * - * @param resource $out - */ - public function __construct($out = NULL) - { - parent::__construct($out); - - $this->prettifier = new PHPUnit_Util_TestDox_NamePrettifier; - $this->startRun(); - } - - /** - * Flush buffer and close output. - * - */ - public function flush() - { - $this->doEndClass(); - $this->endRun(); - - parent::flush(); - } - - /** - * An error occurred. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($test instanceof $this->testTypeOfInterest) { - $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_ERROR; - $this->failed++; - } - } - - /** - * A failure occurred. - * - * @param PHPUnit_Framework_Test $test - * @param PHPUnit_Framework_AssertionFailedError $e - * @param float $time - */ - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - if ($test instanceof $this->testTypeOfInterest) { - $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_FAILURE; - $this->failed++; - } - } - - /** - * Incomplete test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - */ - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($test instanceof $this->testTypeOfInterest) { - $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_INCOMPLETE; - $this->incomplete++; - } - } - - /** - * Skipped test. - * - * @param PHPUnit_Framework_Test $test - * @param Exception $e - * @param float $time - * @since Method available since Release 3.0.0 - */ - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - if ($test instanceof $this->testTypeOfInterest) { - $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_SKIPPED; - $this->skipped++; - } - } - - /** - * A testsuite started. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A testsuite ended. - * - * @param PHPUnit_Framework_TestSuite $suite - * @since Method available since Release 2.2.0 - */ - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - /** - * A test started. - * - * @param PHPUnit_Framework_Test $test - */ - public function startTest(PHPUnit_Framework_Test $test) - { - if ($test instanceof $this->testTypeOfInterest) { - $class = get_class($test); - - if ($this->testClass != $class) { - if ($this->testClass != '') { - $this->doEndClass(); - } - - $this->currentTestClassPrettified = $this->prettifier->prettifyTestClass($class); - $this->startClass($class); - - $this->testClass = $class; - $this->tests = array(); - } - - $prettified = FALSE; - - if ($test instanceof PHPUnit_Framework_TestCase && - !$test instanceof PHPUnit_Framework_Warning) { - $annotations = $test->getAnnotations(); - - if (isset($annotations['method']['testdox'][0])) { - $this->currentTestMethodPrettified = $annotations['method']['testdox'][0]; - $prettified = TRUE; - } - } - - if (!$prettified) { - $this->currentTestMethodPrettified = $this->prettifier->prettifyTestMethod($test->getName(FALSE)); - } - - $this->testStatus = PHPUnit_Runner_BaseTestRunner::STATUS_PASSED; - } - } - - /** - * A test ended. - * - * @param PHPUnit_Framework_Test $test - * @param float $time - */ - public function endTest(PHPUnit_Framework_Test $test, $time) - { - if ($test instanceof $this->testTypeOfInterest) { - if (!isset($this->tests[$this->currentTestMethodPrettified])) { - if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { - $this->tests[$this->currentTestMethodPrettified]['success'] = 1; - $this->tests[$this->currentTestMethodPrettified]['failure'] = 0; - } else { - $this->tests[$this->currentTestMethodPrettified]['success'] = 0; - $this->tests[$this->currentTestMethodPrettified]['failure'] = 1; - } - } else { - if ($this->testStatus == PHPUnit_Runner_BaseTestRunner::STATUS_PASSED) { - $this->tests[$this->currentTestMethodPrettified]['success']++; - } else { - $this->tests[$this->currentTestMethodPrettified]['failure']++; - } - } - - $this->currentTestClassPrettified = NULL; - $this->currentTestMethodPrettified = NULL; - } - } - - /** - * @since Method available since Release 2.3.0 - */ - protected function doEndClass() - { - foreach ($this->tests as $name => $data) { - $this->onTest($name, $data['failure'] == 0); - } - - $this->endClass($this->testClass); - } - - /** - * Handler for 'start run' event. - * - */ - protected function startRun() - { - } - - /** - * Handler for 'start class' event. - * - * @param string $name - */ - protected function startClass($name) - { - } - - /** - * Handler for 'on test' event. - * - * @param string $name - * @param boolean $success - */ - protected function onTest($name, $success = TRUE) - { - } - - /** - * Handler for 'end class' event. - * - * @param string $name - */ - protected function endClass($name) - { - } - - /** - * Handler for 'end run' event. - * - */ - protected function endRun() - { - } -} diff --git a/PHPUnit/Util/TestDox/ResultPrinter/HTML.php b/PHPUnit/Util/TestDox/ResultPrinter/HTML.php deleted file mode 100644 index ff735de99b2..00000000000 --- a/PHPUnit/Util/TestDox/ResultPrinter/HTML.php +++ /dev/null @@ -1,123 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * Prints TestDox documentation in HTML format. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -class PHPUnit_Util_TestDox_ResultPrinter_HTML extends PHPUnit_Util_TestDox_ResultPrinter -{ - /** - * @var boolean - */ - protected $printsHTML = TRUE; - - /** - * Handler for 'start run' event. - * - */ - protected function startRun() - { - $this->write(''); - } - - /** - * Handler for 'start class' event. - * - * @param string $name - */ - protected function startClass($name) - { - $this->write( - '

' . $this->currentTestClassPrettified . - '

    ' - ); - } - - /** - * Handler for 'on test' event. - * - * @param string $name - * @param boolean $success - */ - protected function onTest($name, $success = TRUE) - { - if (!$success) { - $strikeOpen = ''; - $strikeClose = ''; - } else { - $strikeOpen = ''; - $strikeClose = ''; - } - - $this->write('
  • ' . $strikeOpen . $name . $strikeClose . '
  • '); - } - - /** - * Handler for 'end class' event. - * - * @param string $name - */ - protected function endClass($name) - { - $this->write('
'); - } - - /** - * Handler for 'end run' event. - * - */ - protected function endRun() - { - $this->write(''); - } -} diff --git a/PHPUnit/Util/TestDox/ResultPrinter/Text.php b/PHPUnit/Util/TestDox/ResultPrinter/Text.php deleted file mode 100644 index 56c60e8a5e1..00000000000 --- a/PHPUnit/Util/TestDox/ResultPrinter/Text.php +++ /dev/null @@ -1,95 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * Prints TestDox documentation in text format. - * - * @package PHPUnit - * @subpackage Util_TestDox - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -class PHPUnit_Util_TestDox_ResultPrinter_Text extends PHPUnit_Util_TestDox_ResultPrinter -{ - /** - * Handler for 'start class' event. - * - * @param string $name - */ - protected function startClass($name) - { - $this->write($this->currentTestClassPrettified . "\n"); - } - - /** - * Handler for 'on test' event. - * - * @param string $name - * @param boolean $success - */ - protected function onTest($name, $success = TRUE) - { - if ($success) { - $this->write(' [x] '); - } else { - $this->write(' [ ] '); - } - - $this->write($name . "\n"); - } - - /** - * Handler for 'end class' event. - * - * @param string $name - */ - protected function endClass($name) - { - $this->write("\n"); - } -} diff --git a/PHPUnit/Util/TestSuiteIterator.php b/PHPUnit/Util/TestSuiteIterator.php deleted file mode 100644 index 82cc74d0950..00000000000 --- a/PHPUnit/Util/TestSuiteIterator.php +++ /dev/null @@ -1,148 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.1.0 - */ - -/** - * Iterator for test suites. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.1.0 - */ -class PHPUnit_Util_TestSuiteIterator implements RecursiveIterator -{ - /** - * @var integer - */ - protected $position; - - /** - * @var PHPUnit_Framework_Test[] - */ - protected $tests; - - /** - * Constructor. - * - * @param PHPUnit_Framework_TestSuite $suite - */ - public function __construct(PHPUnit_Framework_TestSuite $testSuite) - { - $this->tests = $testSuite->tests(); - } - - /** - * Rewinds the Iterator to the first element. - * - */ - public function rewind() - { - $this->position = 0; - } - - /** - * Checks if there is a current element after calls to rewind() or next(). - * - * @return boolean - */ - public function valid() - { - return $this->position < count($this->tests); - } - - /** - * Returns the key of the current element. - * - * @return integer - */ - public function key() - { - return $this->position; - } - - /** - * Returns the current element. - * - * @return PHPUnit_Framework_Test - */ - public function current() - { - return $this->valid() ? $this->tests[$this->position] : NULL; - } - - /** - * Moves forward to next element. - * - */ - public function next() - { - $this->position++; - } - - /** - * Returns the sub iterator for the current element. - * - * @return PHPUnit_Util_TestSuiteIterator - */ - public function getChildren() - { - return new PHPUnit_Util_TestSuiteIterator( - $this->tests[$this->position] - ); - } - - /** - * Checks whether the current element has children. - * - * @return boolean - */ - public function hasChildren() - { - return $this->tests[$this->position] instanceof PHPUnit_Framework_TestSuite; - } -} diff --git a/PHPUnit/Util/Type.php b/PHPUnit/Util/Type.php deleted file mode 100644 index cd0cef88bb5..00000000000 --- a/PHPUnit/Util/Type.php +++ /dev/null @@ -1,79 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -/** - * Utility class for textual type (and value) representation. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class PHPUnit_Util_Type -{ - public static function isType($type) - { - return in_array( - $type, - array( - 'numeric', - 'integer', - 'int', - 'float', - 'string', - 'boolean', - 'bool', - 'null', - 'array', - 'object', - 'resource', - 'scalar' - ) - ); - } -} diff --git a/PHPUnit/Util/XML.php b/PHPUnit/Util/XML.php deleted file mode 100644 index 631f6f5dc0a..00000000000 --- a/PHPUnit/Util/XML.php +++ /dev/null @@ -1,921 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.2.0 - */ - -/** - * XML helpers. - * - * @package PHPUnit - * @subpackage Util - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.2.0 - */ -class PHPUnit_Util_XML -{ - /** - * Escapes a string for the use in XML documents - * Any Unicode character is allowed, excluding the surrogate blocks, FFFE, - * and FFFF (not even as character reference). - * See http://www.w3.org/TR/xml/#charsets - * - * @param string $string - * @return string - * @author Kore Nordmann - * @since Method available since Release 3.4.6 - */ - public static function prepareString($string) - { - return preg_replace( - '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/', - '', - htmlspecialchars( - PHPUnit_Util_String::convertToUtf8($string), ENT_QUOTES, 'UTF-8' - ) - ); - } - - /** - * Loads an XML (or HTML) file into a DOMDocument object. - * - * @param string $filename - * @param boolean $isHtml - * @param boolean $xinclude - * @return DOMDocument - * @since Method available since Release 3.3.0 - */ - public static function loadFile($filename, $isHtml = FALSE, $xinclude = FALSE) - { - $reporting = error_reporting(0); - $contents = file_get_contents($filename); - error_reporting($reporting); - - if ($contents === FALSE) { - throw new PHPUnit_Framework_Exception( - sprintf( - 'Could not read "%s".', - $filename - ) - ); - } - - return self::load($contents, $isHtml, $filename, $xinclude); - } - - /** - * Load an $actual document into a DOMDocument. This is called - * from the selector assertions. - * - * If $actual is already a DOMDocument, it is returned with - * no changes. Otherwise, $actual is loaded into a new DOMDocument - * as either HTML or XML, depending on the value of $isHtml. If $isHtml is - * false and $xinclude is true, xinclude is performed on the loaded - * DOMDocument. - * - * Note: prior to PHPUnit 3.3.0, this method loaded a file and - * not a string as it currently does. To load a file into a - * DOMDocument, use loadFile() instead. - * - * @param string|DOMDocument $actual - * @param boolean $isHtml - * @param string $filename - * @param boolean $xinclude - * @return DOMDocument - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - * @author Tobias Schlitt - */ - public static function load($actual, $isHtml = FALSE, $filename = '', $xinclude = FALSE) - { - if ($actual instanceof DOMDocument) { - return $actual; - } - - $document = new DOMDocument; - - $internal = libxml_use_internal_errors(TRUE); - $message = ''; - $reporting = error_reporting(0); - - if ($isHtml) { - $loaded = $document->loadHTML($actual); - } else { - $loaded = $document->loadXML($actual); - } - - if ('' !== $filename) { - // Necessary for xinclude - $document->documentURI = $filename; - } - - if (!$isHtml && $xinclude) { - $document->xinclude(); - } - - foreach (libxml_get_errors() as $error) { - $message .= $error->message; - } - - libxml_use_internal_errors($internal); - error_reporting($reporting); - - if ($loaded === FALSE) { - if ($filename != '') { - throw new PHPUnit_Framework_Exception( - sprintf( - 'Could not load "%s".%s', - - $filename, - $message != '' ? "\n" . $message : '' - ) - ); - } else { - throw new PHPUnit_Framework_Exception($message); - } - } - - return $document; - } - - /** - * - * - * @param DOMNode $node - * @return string - * @since Method available since Release 3.4.0 - */ - public static function nodeToText(DOMNode $node) - { - if ($node->childNodes->length == 1) { - return $node->nodeValue; - } - - $result = ''; - - foreach ($node->childNodes as $childNode) { - $result .= $node->ownerDocument->saveXML($childNode); - } - - return $result; - } - - /** - * - * - * @param DOMNode $node - * @since Method available since Release 3.3.0 - * @author Mattis Stordalen Flister - */ - public static function removeCharacterDataNodes(DOMNode $node) - { - if ($node->hasChildNodes()) { - for ($i = $node->childNodes->length - 1; $i >= 0; $i--) { - if (($child = $node->childNodes->item($i)) instanceof DOMCharacterData) { - $node->removeChild($child); - } - } - } - } - - /** - * "Convert" a DOMElement object into a PHP variable. - * - * @param DOMElement $element - * @return mixed - * @since Method available since Release 3.4.0 - */ - public static function xmlToVariable(DOMElement $element) - { - $variable = NULL; - - switch ($element->tagName) { - case 'array': { - $variable = array(); - - foreach ($element->getElementsByTagName('element') as $element) { - $value = self::xmlToVariable($element->childNodes->item(1)); - - if ($element->hasAttribute('key')) { - $variable[(string)$element->getAttribute('key')] = $value; - } else { - $variable[] = $value; - } - } - } - break; - - case 'object': { - $className = $element->getAttribute('class'); - - if ($element->hasChildNodes()) { - $arguments = $element->childNodes->item(1)->childNodes; - $constructorArgs = array(); - - foreach ($arguments as $argument) { - if ($argument instanceof DOMElement) { - $constructorArgs[] = self::xmlToVariable($argument); - } - } - - $class = new ReflectionClass($className); - $variable = $class->newInstanceArgs($constructorArgs); - } else { - $variable = new $className; - } - } - break; - - case 'boolean': { - $variable = $element->nodeValue == 'true' ? TRUE : FALSE; - } - break; - - case 'integer': - case 'double': - case 'string': { - $variable = $element->nodeValue; - - settype($variable, $element->tagName); - } - break; - } - - return $variable; - } - - /** - * Validate list of keys in the associative array. - * - * @param array $hash - * @param array $validKeys - * @return array - * @throws PHPUnit_Framework_Exception - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function assertValidKeys(array $hash, array $validKeys) - { - $valids = array(); - - // Normalize validation keys so that we can use both indexed and - // associative arrays. - foreach ($validKeys as $key => $val) { - is_int($key) ? $valids[$val] = NULL : $valids[$key] = $val; - } - - $validKeys = array_keys($valids); - - // Check for invalid keys. - foreach ($hash as $key => $value) { - if (!in_array($key, $validKeys)) { - $unknown[] = $key; - } - } - - if (!empty($unknown)) { - throw new PHPUnit_Framework_Exception( - 'Unknown key(s): ' . implode(', ', $unknown) - ); - } - - // Add default values for any valid keys that are empty. - foreach ($valids as $key => $value) { - if (!isset($hash[$key])) { - $hash[$key] = $value; - } - } - - return $hash; - } - - /** - * Parse a CSS selector into an associative array suitable for - * use with findNodes(). - * - * @param string $selector - * @param mixed $content - * @return array - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - public static function convertSelectToTag($selector, $content = TRUE) - { - $selector = trim(preg_replace("/\s+/", " ", $selector)); - - // substitute spaces within attribute value - while (preg_match('/\[[^\]]+"[^"]+\s[^"]+"\]/', $selector)) { - $selector = preg_replace( - '/(\[[^\]]+"[^"]+)\s([^"]+"\])/', "$1__SPACE__$2", $selector - ); - } - - if (strstr($selector, ' ')) { - $elements = explode(' ', $selector); - } else { - $elements = array($selector); - } - - $previousTag = array(); - - foreach (array_reverse($elements) as $element) { - $element = str_replace('__SPACE__', ' ', $element); - - // child selector - if ($element == '>') { - $previousTag = array('child' => $previousTag['descendant']); - continue; - } - - $tag = array(); - - // match element tag - preg_match("/^([^\.#\[]*)/", $element, $eltMatches); - - if (!empty($eltMatches[1])) { - $tag['tag'] = $eltMatches[1]; - } - - // match attributes (\[[^\]]*\]*), ids (#[^\.#\[]*), - // and classes (\.[^\.#\[]*)) - preg_match_all( - "/(\[[^\]]*\]*|#[^\.#\[]*|\.[^\.#\[]*)/", $element, $matches - ); - - if (!empty($matches[1])) { - $classes = array(); - $attrs = array(); - - foreach ($matches[1] as $match) { - // id matched - if (substr($match, 0, 1) == '#') { - $tag['id'] = substr($match, 1); - } - - // class matched - else if (substr($match, 0, 1) == '.') { - $classes[] = substr($match, 1); - } - - // attribute matched - else if (substr($match, 0, 1) == '[' && - substr($match, -1, 1) == ']') { - $attribute = substr($match, 1, strlen($match) - 2); - $attribute = str_replace('"', '', $attribute); - - // match single word - if (strstr($attribute, '~=')) { - list($key, $value) = explode('~=', $attribute); - $value = "regexp:/.*\b$value\b.*/"; - } - - // match substring - else if (strstr($attribute, '*=')) { - list($key, $value) = explode('*=', $attribute); - $value = "regexp:/.*$value.*/"; - } - - // exact match - else { - list($key, $value) = explode('=', $attribute); - } - - $attrs[$key] = $value; - } - } - - if ($classes) { - $tag['class'] = join(' ', $classes); - } - - if ($attrs) { - $tag['attributes'] = $attrs; - } - } - - // tag content - if (is_string($content)) { - $tag['content'] = $content; - } - - // determine previous child/descendants - if (!empty($previousTag['descendant'])) { - $tag['descendant'] = $previousTag['descendant']; - } - - else if (!empty($previousTag['child'])) { - $tag['child'] = $previousTag['child']; - } - - $previousTag = array('descendant' => $tag); - } - - return $tag; - } - - /** - * Parse an $actual document and return an array of DOMNodes - * matching the CSS $selector. If an error occurs, it will - * return FALSE. - * - * To only return nodes containing a certain content, give - * the $content to match as a string. Otherwise, setting - * $content to TRUE will return all nodes matching $selector. - * - * The $actual document may be a DOMDocument or a string - * containing XML or HTML, identified by $isHtml. - * - * @param array $selector - * @param string $content - * @param mixed $actual - * @param boolean $isHtml - * @return boolean|array - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - * @author Tobias Schlitt - */ - public static function cssSelect($selector, $content, $actual, $isHtml = TRUE) - { - $matcher = self::convertSelectToTag($selector, $content); - $dom = self::load($actual, $isHtml); - $tags = self::findNodes($dom, $matcher, $isHtml); - - return $tags; - } - - /** - * Parse out the options from the tag using DOM object tree. - * - * @param DOMDocument $dom - * @param array $options - * @param boolean $isHtml - * @return array - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - * @author Tobias Schlitt - */ - public static function findNodes(DOMDocument $dom, array $options, $isHtml = TRUE) - { - $valid = array( - 'id', 'class', 'tag', 'content', 'attributes', 'parent', - 'child', 'ancestor', 'descendant', 'children' - ); - - $filtered = array(); - $options = self::assertValidKeys($options, $valid); - - // find the element by id - if ($options['id']) { - $options['attributes']['id'] = $options['id']; - } - - if ($options['class']) { - $options['attributes']['class'] = $options['class']; - } - - // find the element by a tag type - if ($options['tag']) { - if ($isHtml) { - $elements = self::getElementsByCaseInsensitiveTagName( - $dom, $options['tag'] - ); - } else { - $elements = $dom->getElementsByTagName($options['tag']); - } - - foreach ($elements as $element) { - $nodes[] = $element; - } - - if (empty($nodes)) { - return FALSE; - } - } - - // no tag selected, get them all - else { - $tags = array( - 'a', 'abbr', 'acronym', 'address', 'area', 'b', 'base', 'bdo', - 'big', 'blockquote', 'body', 'br', 'button', 'caption', 'cite', - 'code', 'col', 'colgroup', 'dd', 'del', 'div', 'dfn', 'dl', - 'dt', 'em', 'fieldset', 'form', 'frame', 'frameset', 'h1', 'h2', - 'h3', 'h4', 'h5', 'h6', 'head', 'hr', 'html', 'i', 'iframe', - 'img', 'input', 'ins', 'kbd', 'label', 'legend', 'li', 'link', - 'map', 'meta', 'noframes', 'noscript', 'object', 'ol', 'optgroup', - 'option', 'p', 'param', 'pre', 'q', 'samp', 'script', 'select', - 'small', 'span', 'strong', 'style', 'sub', 'sup', 'table', - 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'title', - 'tr', 'tt', 'ul', 'var' - ); - - foreach ($tags as $tag) { - if ($isHtml) { - $elements = self::getElementsByCaseInsensitiveTagName( - $dom, $tag - ); - } else { - $elements = $dom->getElementsByTagName($tag); - } - - foreach ($elements as $element) { - $nodes[] = $element; - } - } - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by attributes - if ($options['attributes']) { - foreach ($nodes as $node) { - $invalid = FALSE; - - foreach ($options['attributes'] as $name => $value) { - // match by regexp if like "regexp:/foo/i" - if (preg_match('/^regexp\s*:\s*(.*)/i', $value, $matches)) { - if (!preg_match($matches[1], $node->getAttribute($name))) { - $invalid = TRUE; - } - } - - // class can match only a part - else if ($name == 'class') { - // split to individual classes - $findClasses = explode( - ' ', preg_replace("/\s+/", " ", $value) - ); - - $allClasses = explode( - ' ', - preg_replace("/\s+/", " ", $node->getAttribute($name)) - ); - - // make sure each class given is in the actual node - foreach ($findClasses as $findClass) { - if (!in_array($findClass, $allClasses)) { - $invalid = TRUE; - } - } - } - - // match by exact string - else { - if ($node->getAttribute($name) != $value) { - $invalid = TRUE; - } - } - } - - // if every attribute given matched - if (!$invalid) { - $filtered[] = $node; - } - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by content - if ($options['content'] !== NULL) { - foreach ($nodes as $node) { - $invalid = FALSE; - - // match by regexp if like "regexp:/foo/i" - if (preg_match('/^regexp\s*:\s*(.*)/i', $options['content'], $matches)) { - if (!preg_match($matches[1], self::getNodeText($node))) { - $invalid = TRUE; - } - } - - // match empty string - else if ($options['content'] === '') { - if (self::getNodeText($node) !== '') { - $invalid = TRUE; - } - } - - // match by exact string - else if (strstr(self::getNodeText($node), $options['content']) === FALSE) { - $invalid = TRUE; - } - - if (!$invalid) { - $filtered[] = $node; - } - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by parent node - if ($options['parent']) { - $parentNodes = self::findNodes($dom, $options['parent'], $isHtml); - $parentNode = isset($parentNodes[0]) ? $parentNodes[0] : NULL; - - foreach ($nodes as $node) { - if ($parentNode !== $node->parentNode) { - continue; - } - - $filtered[] = $node; - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by child node - if ($options['child']) { - $childNodes = self::findNodes($dom, $options['child'], $isHtml); - $childNodes = !empty($childNodes) ? $childNodes : array(); - - foreach ($nodes as $node) { - foreach ($node->childNodes as $child) { - foreach ($childNodes as $childNode) { - if ($childNode === $child) { - $filtered[] = $node; - } - } - } - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by ancestor - if ($options['ancestor']) { - $ancestorNodes = self::findNodes($dom, $options['ancestor'], $isHtml); - $ancestorNode = isset($ancestorNodes[0]) ? $ancestorNodes[0] : NULL; - - foreach ($nodes as $node) { - $parent = $node->parentNode; - - while ($parent && $parent->nodeType != XML_HTML_DOCUMENT_NODE) { - if ($parent === $ancestorNode) { - $filtered[] = $node; - } - - $parent = $parent->parentNode; - } - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by descendant - if ($options['descendant']) { - $descendantNodes = self::findNodes($dom, $options['descendant'], $isHtml); - $descendantNodes = !empty($descendantNodes) ? $descendantNodes : array(); - - foreach ($nodes as $node) { - foreach (self::getDescendants($node) as $descendant) { - foreach ($descendantNodes as $descendantNode) { - if ($descendantNode === $descendant) { - $filtered[] = $node; - } - } - } - } - - $nodes = $filtered; - $filtered = array(); - - if (empty($nodes)) { - return FALSE; - } - } - - // filter by children - if ($options['children']) { - $validChild = array('count', 'greater_than', 'less_than', 'only'); - $childOptions = self::assertValidKeys( - $options['children'], $validChild - ); - - foreach ($nodes as $node) { - $childNodes = $node->childNodes; - - foreach ($childNodes as $childNode) { - if ($childNode->nodeType !== XML_CDATA_SECTION_NODE && - $childNode->nodeType !== XML_TEXT_NODE) { - $children[] = $childNode; - } - } - - // we must have children to pass this filter - if (!empty($children)) { - // exact count of children - if ($childOptions['count'] !== NULL) { - if (count($children) !== $childOptions['count']) { - break; - } - } - - // range count of children - else if ($childOptions['less_than'] !== NULL && - $childOptions['greater_than'] !== NULL) { - if (count($children) >= $childOptions['less_than'] || - count($children) <= $childOptions['greater_than']) { - break; - } - } - - // less than a given count - else if ($childOptions['less_than'] !== NULL) { - if (count($children) >= $childOptions['less_than']) { - break; - } - } - - // more than a given count - else if ($childOptions['greater_than'] !== NULL) { - if (count($children) <= $childOptions['greater_than']) { - break; - } - } - - // match each child against a specific tag - if ($childOptions['only']) { - $onlyNodes = self::findNodes( - $dom, $childOptions['only'], $isHtml - ); - - // try to match each child to one of the 'only' nodes - foreach ($children as $child) { - $matched = FALSE; - - foreach ($onlyNodes as $onlyNode) { - if ($onlyNode === $child) { - $matched = TRUE; - } - } - - if (!$matched) { - break(2); - } - } - } - - $filtered[] = $node; - } - } - - $nodes = $filtered; - - if (empty($nodes)) { - return; - } - } - - // return the first node that matches all criteria - return !empty($nodes) ? $nodes : array(); - } - - /** - * Recursively get flat array of all descendants of this node. - * - * @param DOMNode $node - * @return array - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - protected static function getDescendants(DOMNode $node) - { - $allChildren = array(); - $childNodes = $node->childNodes ? $node->childNodes : array(); - - foreach ($childNodes as $child) { - if ($child->nodeType === XML_CDATA_SECTION_NODE || - $child->nodeType === XML_TEXT_NODE) { - continue; - } - - $children = self::getDescendants($child); - $allChildren = array_merge($allChildren, $children, array($child)); - } - - return isset($allChildren) ? $allChildren : array(); - } - - /** - * Gets elements by case insensitive tagname. - * - * @param DOMDocument $dom - * @param string $tag - * @return DOMNodeList - * @since Method available since Release 3.4.0 - */ - protected static function getElementsByCaseInsensitiveTagName(DOMDocument $dom, $tag) - { - $elements = $dom->getElementsByTagName(strtolower($tag)); - - if ($elements->length == 0) { - $elements = $dom->getElementsByTagName(strtoupper($tag)); - } - - return $elements; - } - - /** - * Get the text value of this node's child text node. - * - * @param DOMNode $node - * @return string - * @since Method available since Release 3.3.0 - * @author Mike Naberezny - * @author Derek DeVries - */ - protected static function getNodeText(DOMNode $node) - { - if (!$node->childNodes instanceof DOMNodeList) { - return ''; - } - - $result = ''; - - foreach ($node->childNodes as $childNode) { - if ($childNode->nodeType === XML_TEXT_NODE || - $childNode->nodeType === XML_CDATA_SECTION_NODE) { - $result .= trim($childNode->data) . ' '; - } else { - $result .= self::getNodeText($childNode); - } - } - - return str_replace(' ', ' ', $result); - } -} diff --git a/README.md b/README.md index 00bbb651e13..4df3a31c84a 100644 --- a/README.md +++ b/README.md @@ -1,75 +1,108 @@ -# PHPUnit +[![PHPUnit](.github/img/phpunit.svg)](https://phpunit.de/?ref=github) -PHPUnit is the de-facto standard for unit testing in PHP projects. It provides both a framework that makes the writing of tests easy as well as the functionality to easily run the tests and analyse their results. +[![CI Status](https://github.com/sebastianbergmann/phpunit/workflows/CI/badge.svg)](https://github.com/sebastianbergmann/phpunit/actions) +[![codecov](https://codecov.io/gh/sebastianbergmann/phpunit/branch/main/graph/badge.svg?token=0yzBUK8Wri)](https://codecov.io/gh/sebastianbergmann/phpunit) +[![Latest Stable Version](https://poser.pugx.org/phpunit/phpunit/v)](https://packagist.org/packages/phpunit/phpunit) +[![Total Downloads](https://poser.pugx.org/phpunit/phpunit/downloads)](https://packagist.org/packages/phpunit/phpunit/stats) +[![Monthly Downloads](https://poser.pugx.org/phpunit/phpunit/d/monthly)](https://packagist.org/packages/phpunit/phpunit/stats) +[![Daily Downloads](https://poser.pugx.org/phpunit/phpunit/d/daily)](https://packagist.org/packages/phpunit/phpunit/stats) -## Requirements +# PHPUnit -* PHPUnit 3.8 requires PHP 5.4.7 (or later). -* [PHP_CodeCoverage](http://github.com/sebastianbergmann/php-code-coverage), the library that is used by PHPUnit to collect and process code coverage information, depends on [Xdebug](http://xdebug.org/) 2.2.1 (or later). +PHPUnit is a programmer-oriented testing framework for PHP. +It is an instance of the xUnit architecture for unit testing frameworks. ## Installation -There are three supported ways of installing PHPUnit. - -You can use the [PEAR Installer](http://pear.php.net/manual/en/guide.users.commandline.cli.php) or [Composer](http://getcomposer.org/) to download and install PHPUnit as well as its dependencies. You can also download a [PHP Archive (PHAR)](http://php.net/phar) of PHPUnit that has all required (as well as some optional) dependencies of PHPUnit bundled in a single file. - -### PEAR Installer - -The following two commands (which you may have to run as `root`) are all that is required to install PHPUnit using the PEAR Installer: - - pear config-set auto_discover 1 - pear install pear.phpunit.de/PHPUnit - -### Composer - -To add PHPUnit as a local, per-project dependency to your project, simply add a dependency on `phpunit/phpunit` to your project's `composer.json` file. Here is a minimal example of a `composer.json` file that just defines a development-time dependency on PHPUnit 3.7: - - { - "require-dev": { - "phpunit/phpunit": "3.7.*" - } - } - -### PHP Archive (PHAR) - - wget http://pear.phpunit.de/get/phpunit.phar - chmod +x phpunit.phar - -## Documentation - -The documentation for PHPUnit is available in different formats: - -* [English, multiple HTML files](http://www.phpunit.de/manual/current/en/index.html) -* [English, single HTML file](http://www.phpunit.de/manual/current/en/phpunit-book.html) -* [English, PDF](http://www.phpunit.de/manual/current/en/phpunit-book.pdf) -* [English, ePub](http://www.phpunit.de/manual/current/en/phpunit-book.epub) -* [Brazilian Portuguese, multiple HTML files](http://www.phpunit.de/manual/current/pt_br/index.html) -* [Brazilian Portuguese, single HTML file](http://www.phpunit.de/manual/current/pt_br/phpunit-book.html) -* [Brazilian Portuguese, PDF](http://www.phpunit.de/manual/current/pt_br/phpunit-book.pdf) -* [Brazilian Portuguese, ePub](http://www.phpunit.de/manual/current/pt_br/phpunit-book.epub) -* [French, multiple HTML files](http://www.phpunit.de/manual/current/fr/index.html) -* [French, single HTML file](http://www.phpunit.de/manual/current/fr/phpunit-book.html) -* [French, PDF](http://www.phpunit.de/manual/current/fr/phpunit-book.pdf) -* [French, ePub](http://www.phpunit.de/manual/current/fr/phpunit-book.epub) -* [Japanese, multiple HTML files](http://www.phpunit.de/manual/current/ja/index.html) -* [Japanese, single HTML file](http://www.phpunit.de/manual/current/ja/phpunit-book.html) -* [Japanese, PDF](http://www.phpunit.de/manual/current/ja/phpunit-book.pdf) -* [Japanese, ePub](http://www.phpunit.de/manual/current/ja/phpunit-book.epub) - -## IRC - -The [#phpunit channel on the Freenode IRC network](irc://irc.freenode.net/phpunit) is a place to chat about PHPUnit. - -## List of Contributors - -Thanks to everyone who has contributed to PHPUnit! You can find a detailed list of contributors on every PHPUnit related package on GitHub. This list shows only the major components: - -* [PHPUnit](https://github.com/sebastianbergmann/phpunit/graphs/contributors) -* [PHP_CodeCoverage](https://github.com/sebastianbergmann/php-code-coverage/graphs/contributors) -* [PHPUnit_MockObject](https://github.com/sebastianbergmann/phpunit-mock-objects/graphs/contributors) - -A very special thanks to everyone who has contributed to the documentation and helps maintaining the translations: - -* [PHPUnit Documentation](https://github.com/sebastianbergmann/phpunit-documentation/graphs/contributors) - -Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/master/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects. +We distribute a [PHP Archive (PHAR)](https://php.net/phar) that has all required dependencies of PHPUnit bundled in a single file: + +```bash +$ wget https://phar.phpunit.de/phpunit-X.Y.phar + +$ php phpunit-X.Y.phar --version +``` + +Please replace `X.Y` with the version of PHPUnit you are interested in. + +Alternatively, you may use [Composer](https://getcomposer.org/) to download and install PHPUnit as well as its dependencies. +Please refer to the [documentation](https://phpunit.de/documentation.html?ref=github) for details on how to install PHPUnit. + +## Contribute + +Please refer to [CONTRIBUTING.md](https://github.com/sebastianbergmann/phpunit/blob/main/.github/CONTRIBUTING.md) for information on how to contribute to PHPUnit and its related projects. + +A big "Thank you!" to everyone who has contributed to PHPUnit! +You can find a detailed list of contributors on every PHPUnit related package on GitHub. + +Here is a list of all components that are primarily developed and maintained by [Sebastian Bergmann](https://sebastian-bergmann.de/open-source.html?ref=github): + +* [phpunit/phpunit](https://github.com/sebastianbergmann/phpunit) +* [phpunit/php-code-coverage](https://github.com/sebastianbergmann/php-code-coverage) +* [phpunit/php-file-iterator](https://github.com/sebastianbergmann/php-file-iterator) +* [phpunit/php-invoker](https://github.com/sebastianbergmann/php-invoker) +* [phpunit/php-text-template](https://github.com/sebastianbergmann/php-text-template) +* [phpunit/php-timer](https://github.com/sebastianbergmann/php-timer) +* [sebastian/cli-parser](https://github.com/sebastianbergmann/cli-parser) +* [sebastian/comparator](https://github.com/sebastianbergmann/comparator) +* [sebastian/complexity](https://github.com/sebastianbergmann/complexity) +* [sebastian/diff](https://github.com/sebastianbergmann/diff) +* [sebastian/environment](https://github.com/sebastianbergmann/environment) +* [sebastian/exporter](https://github.com/sebastianbergmann/exporter) +* [sebastian/global-state](https://github.com/sebastianbergmann/global-state) +* [sebastian/lines-of-code](https://github.com/sebastianbergmann/lines-of-code) +* [sebastian/object-enumerator](https://github.com/sebastianbergmann/object-enumerator) +* [sebastian/object-reflector](https://github.com/sebastianbergmann/object-reflector) +* [sebastian/recursion-context](https://github.com/sebastianbergmann/recursion-context) +* [sebastian/type](https://github.com/sebastianbergmann/type) +* [sebastian/version](https://github.com/sebastianbergmann/version) + +A very special thanks to everyone who has contributed to the [PHPUnit Manual](https://github.com/sebastianbergmann/phpunit-documentation-english). + +In addition to the components listed above, PHPUnit depends on the components listed below: + +* [myclabs/deep-copy](https://github.com/myclabs/DeepCopy) +* [nikic/php-parser](https://github.com/nikic/php-parser) +* [phar-io/manifest](https://github.com/phar-io/manifest) +* [phar-io/version](https://github.com/phar-io/version) +* [staabm/side-effects-detector](https://github.com/staabm/side-effects-detector) +* [theseer/tokenizer](https://github.com/theseer/tokenizer) + +These tools are used to develop PHPUnit: + +* [Composer](https://getcomposer.org/) +* [Phive](https://phar.io/) +* [PHP Autoload Builder](https://github.com/theseer/Autoload/) +* [PHP-CS-Fixer](https://cs.symfony.com/) +* [PHP-Scoper](https://github.com/humbug/php-scoper) +* [PHPStan](https://phpstan.org/) + +## Sponsors + +It has taken [Sebastian Bergmann](https://sebastian-bergmann.de/open-source.html?ref=github) thousands of hours to develop, test, and support PHPUnit. +[**You can sponsor his Open Source work through GitHub Sponsors**](https://github.com/sponsors/sebastianbergmann), for example. + +These businesses support Sebastian Bergmann's work on PHPUnit: + + + + + + + + + + + + + + + + + +
Bubble Shooterin2it vofLambdaTest
Testmo GmbHTideways GmbHTYPO3 GmbH
VEMA Versicherungsmakler Genossenschaft eG
+ +Would you like to see your logo here as well as on the [PHPUnit website](https://phpunit.de/sponsors.html?ref=github)? +Contact Sebastian Bergmann at [sponsoring@phpunit.de](mailto:sponsoring@phpunit.de) to learn more about how you can support his work on PHPUnit. + +Whether you are a CEO, CFO, CTO, or a developer: your company surely depends on Open Source software. +[It is time to pay your share](https://opensourcepledge.com/) and support maintainers like [Sebastian Bergmann](https://sebastian-bergmann.de/open-source.html?ref=github). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..5f55c41947b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,33 @@ +# Security Policy + +If you believe you have found a security vulnerability in PHPUnit, please report it to us through coordinated disclosure. + +**Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** + +Instead, please email `sebastian@phpunit.de`. + +Please include as much of the information listed below as you can to help us better understand and resolve the issue: + +* The type of issue +* Full paths of source file(s) related to the manifestation of the issue +* The location of the affected source code (tag/branch/commit or direct URL) +* Any special configuration required to reproduce the issue +* Step-by-step instructions to reproduce the issue +* Proof-of-concept or exploit code (if possible) +* Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Web Context + +PHPUnit is a framework for writing as well as a command-line tool for running tests. Writing and running tests is a development-time activity. There is no reason why PHPUnit should be installed on a webserver and/or in a production environment. + +**If you upload PHPUnit to a webserver then your deployment process is broken. On a more general note, if your `vendor` directory is publicly accessible on your webserver then your deployment process is also broken.** + +Please note that if you upload PHPUnit to a webserver "bad things" may happen. [You have been warned.](https://thephp.cc/articles/phpunit-a-security-risk?ref=phpunit) + +PHPUnit is developed with a focus on development environments and the command-line. No specific testing or hardening with regard to using PHPUnit in an HTTP or web context or with untrusted input data is performed. PHPUnit might also contain functionality that intentionally exposes internal application data for debugging purposes. + +If PHPUnit is used in a web application, the application developer is responsible for filtering inputs or escaping outputs as necessary and for verifying that the used functionality is safe for use within the intended context. + +Vulnerabilities specific to the use outside a development context will be fixed as applicable, provided that the fix does not have an averse effect on the primary use case for development purposes. diff --git a/Tests/Extensions/RepeatedTestTest.php b/Tests/Extensions/RepeatedTestTest.php deleted file mode 100644 index 2646f3dd2c4..00000000000 --- a/Tests/Extensions/RepeatedTestTest.php +++ /dev/null @@ -1,108 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Extensions_RepeatedTestTest extends PHPUnit_Framework_TestCase -{ - protected $suite; - - public function __construct() - { - $this->suite = new PHPUnit_Framework_TestSuite; - - $this->suite->addTest(new Success); - $this->suite->addTest(new Success); - } - - public function testRepeatedOnce() - { - $test = new PHPUnit_Extensions_RepeatedTest($this->suite, 1); - $this->assertEquals(2, count($test)); - - $result = $test->run(); - $this->assertEquals(2, count($result)); - } - - public function testRepeatedMoreThanOnce() - { - $test = new PHPUnit_Extensions_RepeatedTest($this->suite, 3); - $this->assertEquals(6, count($test)); - - $result = $test->run(); - $this->assertEquals(6, count($result)); - } - - public function testRepeatedZero() - { - $test = new PHPUnit_Extensions_RepeatedTest($this->suite, 0); - $this->assertEquals(0, count($test)); - - $result = $test->run(); - $this->assertEquals(0, count($result)); - } - - public function testRepeatedNegative() - { - try { - $test = new PHPUnit_Extensions_RepeatedTest($this->suite, -1); - } - - catch (Exception $e) { - return; - } - - $this->fail('Should throw an Exception'); - } -} diff --git a/Tests/Framework/AssertTest.php b/Tests/Framework/AssertTest.php deleted file mode 100644 index 09cb86a11f0..00000000000 --- a/Tests/Framework/AssertTest.php +++ /dev/null @@ -1,4335 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithNonPublicAttributes.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'SampleClass.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Struct.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'TestIterator.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Author.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Book.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithToString.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Framework_AssertTest extends PHPUnit_Framework_TestCase -{ - protected $filesDirectory; - - protected function setUp() - { - $this->filesDirectory = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR; - - $this->html = file_get_contents( - $this->filesDirectory . 'SelectorAssertionsFixture.html' - ); - } - - /** - * @covers PHPUnit_Framework_Assert::fail - */ - public function testFail() - { - try { - $this->fail(); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - throw new PHPUnit_Framework_AssertionFailedError('Fail did not throw fail exception'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertSplObjectStorageContainsObject() - { - $a = new stdClass; - $b = new stdClass; - $c = new SplObjectStorage; - $c->attach($a); - - $this->assertContains($a, $c); - - try { - $this->assertContains($b, $c); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertArrayContainsObject() - { - $a = new stdClass; - $b = new stdClass; - - $this->assertContains($a, array($a)); - - try { - $this->assertContains($a, array($b)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertArrayContainsString() - { - $this->assertContains('foo', array('foo')); - - try { - $this->assertContains('foo', array('bar')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertArrayContainsNonObject() - { - $this->assertContains('foo', array(TRUE)); - - try { - $this->assertContains('foo', array(TRUE), '', FALSE, TRUE, TRUE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContainsOnlyInstancesOf - */ - public function testAssertContainsOnlyInstancesOf() - { - $test = array( - new Book(), - new Book - ); - $this->assertContainsOnlyInstancesOf('Book', $test); - $this->assertContainsOnlyInstancesOf('stdClass', array(new stdClass())); - - $test2 = array( - new Author('Test') - ); - try { - $this->assertContainsOnlyInstancesOf('Book', $test2); - } catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayHasKey - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertArrayHasKeyThrowsException() - { - $this->assertArrayHasKey(NULL, array()); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayHasKey - */ - public function testAssertArrayHasIntegerKey() - { - $this->assertArrayHasKey(0, array('foo')); - - try { - $this->assertArrayHasKey(1, array('foo')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayNotHasKey - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertArrayNotHasKeyThrowsException() - { - $this->assertArrayNotHasKey(NULL, array()); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayNotHasKey - */ - public function testAssertArrayNotHasIntegerKey() - { - $this->assertArrayNotHasKey(1, array('foo')); - - try { - $this->assertArrayNotHasKey(0, array('foo')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayHasKey - */ - public function testAssertArrayHasStringKey() - { - $this->assertArrayHasKey('foo', array('foo' => 'bar')); - - try { - $this->assertArrayHasKey('bar', array('foo' => 'bar')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayNotHasKey - */ - public function testAssertArrayNotHasStringKey() - { - $this->assertArrayNotHasKey('bar', array('foo' => 'bar')); - - try { - $this->assertArrayNotHasKey('foo', array('foo' => 'bar')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayHasKey - */ - public function testAssertArrayHasKeyAcceptsArrayAccessValue() - { - $array = new ArrayObject(); - $array['foo'] = 'bar'; - $this->assertArrayHasKey('foo', $array); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayHasKey - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertArrayHasKeyProperlyFailsWithArrayAccessValue() - { - $array = new ArrayObject(); - $array['bar'] = 'bar'; - $this->assertArrayHasKey('foo', $array); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayNotHasKey - */ - public function testAssertArrayNotHasKeyAcceptsArrayAccessValue() - { - $array = new ArrayObject(); - $array['foo'] = 'bar'; - $this->assertArrayNotHasKey('bar', $array); - } - - /** - * @covers PHPUnit_Framework_Assert::assertArrayNotHasKey - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertArrayNotHasKeyPropertlyFailsWithArrayAccessValue() - { - $array = new ArrayObject(); - $array['bar'] = 'bar'; - $this->assertArrayNotHasKey('bar', $array); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertContainsThrowsException() - { - $this->assertContains(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertIteratorContainsObject() - { - $foo = new stdClass; - - $this->assertContains($foo, new TestIterator(array($foo))); - - try { - $this->assertContains($foo, new TestIterator(array(new stdClass))); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertIteratorContainsString() - { - $this->assertContains('foo', new TestIterator(array('foo'))); - - try { - $this->assertContains('foo', new TestIterator(array('bar'))); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContains - */ - public function testAssertStringContainsString() - { - $this->assertContains('foo', 'foobar'); - - try { - $this->assertContains('foo', 'bar'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertNotContainsThrowsException() - { - $this->assertNotContains(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - */ - public function testAssertSplObjectStorageNotContainsObject() - { - $a = new stdClass; - $b = new stdClass; - $c = new SplObjectStorage; - $c->attach($a); - - $this->assertNotContains($b, $c); - - try { - $this->assertNotContains($a, $c); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - */ - public function testAssertArrayNotContainsObject() - { - $a = new stdClass; - $b = new stdClass; - - $this->assertNotContains($a, array($b)); - - try { - $this->assertNotContains($a, array($a)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - */ - public function testAssertArrayNotContainsString() - { - $this->assertNotContains('foo', array('bar')); - - try { - $this->assertNotContains('foo', array('foo')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - */ - public function testAssertArrayNotContainsNonObject() - { - $this->assertNotContains('foo', array(TRUE), '', FALSE, TRUE, TRUE); - - try { - $this->assertNotContains('foo', array(TRUE)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContains - */ - public function testAssertStringNotContainsString() - { - $this->assertNotContains('foo', 'bar'); - - try { - $this->assertNotContains('foo', 'foo'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContainsOnly - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertContainsOnlyThrowsException() - { - $this->assertContainsOnly(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContainsOnlyInstancesOf - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertContainsOnlyInstancesOfThrowsException() - { - $this->assertContainsOnlyInstancesOf(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContainsOnly - */ - public function testAssertArrayContainsOnlyIntegers() - { - $this->assertContainsOnly('integer', array(1, 2, 3)); - - try { - $this->assertContainsOnly('integer', array("1", 2, 3)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContainsOnly - */ - public function testAssertArrayNotContainsOnlyIntegers() - { - $this->assertNotContainsOnly('integer', array("1", 2, 3)); - - try { - $this->assertNotContainsOnly('integer', array(1, 2, 3)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertContainsOnly - */ - public function testAssertArrayContainsOnlyStdClass() - { - $this->assertContainsOnly('StdClass', array(new StdClass)); - - try { - $this->assertContainsOnly('StdClass', array('StdClass')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotContainsOnly - */ - public function testAssertArrayNotContainsOnlyStdClass() - { - $this->assertNotContainsOnly('StdClass', array('StdClass')); - - try { - $this->assertNotContainsOnly('StdClass', array(new StdClass)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - protected function createDOMDocument($content) - { - $document = new DOMDocument; - $document->preserveWhiteSpace = FALSE; - $document->loadXML($content); - - return $document; - } - - protected function sameValues() - { - $object = new SampleClass(4, 8, 15); - // cannot use $filesDirectory, because neither setUp() nor - // setUpBeforeClass() are executed before the data providers - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'foo.xml'; - $resource = fopen($file, 'r'); - - return array( - // NULL - array(NULL, NULL), - // strings - array('a', 'a'), - // integers - array(0, 0), - // floats - array(2.3, 2.3), - array(1/3, 1 - 2/3), - array(log(0), log(0)), - // arrays - array(array(), array()), - array(array(0 => 1), array(0 => 1)), - array(array(0 => NULL), array(0 => NULL)), - array(array('a', 'b' => array(1, 2)), array('a', 'b' => array(1, 2))), - // objects - array($object, $object), - // resources - array($resource, $resource), - ); - } - - protected function notEqualValues() - { - // cyclic dependencies - $book1 = new Book; - $book1->author = new Author('Terry Pratchett'); - $book1->author->books[] = $book1; - $book2 = new Book; - $book2->author = new Author('Terry Pratch'); - $book2->author->books[] = $book2; - - $book3 = new Book; - $book3->author = 'Terry Pratchett'; - $book4 = new stdClass; - $book4->author = 'Terry Pratchett'; - - $object1 = new SampleClass( 4, 8, 15); - $object2 = new SampleClass(16, 23, 42); - $object3 = new SampleClass( 4, 8, 15); - $storage1 = new SplObjectStorage; - $storage1->attach($object1); - $storage2 = new SplObjectStorage; - $storage2->attach($object3); // same content, different object - - // cannot use $filesDirectory, because neither setUp() nor - // setUpBeforeClass() are executed before the data providers - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'foo.xml'; - - return array( - // strings - array('a', 'b'), - array('a', 'A'), - // integers - array(1, 2), - array(2, 1), - // floats - array(2.3, 4.2), - array(2.3, 4.2, 0.5), - array(array(2.3), array(4.2), 0.5), - array(array(array(2.3)), array(array(4.2)), 0.5), - array(new Struct(2.3), new Struct(4.2), 0.5), - array(array(new Struct(2.3)), array(new Struct(4.2)), 0.5), - // NAN - array(NAN, NAN), - // arrays - array(array(), array(0 => 1)), - array(array(0 => 1), array()), - array(array(0 => NULL), array()), - array(array(0 => 1, 1 => 2), array(0 => 1, 1 => 3)), - array(array('a', 'b' => array(1, 2)), array('a', 'b' => array(2, 1))), - // objects - array(new SampleClass(4, 8, 15), new SampleClass(16, 23, 42)), - array($object1, $object2), - array($book1, $book2), - array($book3, $book4), // same content, different class - // resources - array(fopen($file, 'r'), fopen($file, 'r')), - // SplObjectStorage - array($storage1, $storage2), - // DOMDocument - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(' bar '), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(' bar '), - $this->createDOMDocument(' bir '), - ), - // Exception - //array(new Exception('Exception 1'), new Exception('Exception 2')), - // different types - array(new SampleClass(4, 8, 15), FALSE), - array(FALSE, new SampleClass(4, 8, 15)), - array(array(0 => 1, 1 => 2), FALSE), - array(FALSE, array(0 => 1, 1 => 2)), - array(array(), new stdClass), - array(new stdClass, array()), - // PHP: 0 == 'Foobar' => TRUE! - // We want these values to differ - array(0, 'Foobar'), - array('Foobar', 0), - array(3, acos(8)), - array(acos(8), 3) - ); - } - - protected function equalValues() - { - // cyclic dependencies - $book1 = new Book; - $book1->author = new Author('Terry Pratchett'); - $book1->author->books[] = $book1; - $book2 = new Book; - $book2->author = new Author('Terry Pratchett'); - $book2->author->books[] = $book2; - - $object1 = new SampleClass(4, 8, 15); - $object2 = new SampleClass(4, 8, 15); - $storage1 = new SplObjectStorage; - $storage1->attach($object1); - $storage2 = new SplObjectStorage; - $storage2->attach($object1); - - return array( - // strings - array('a', 'A', 0, FALSE, TRUE), // ignore case - // arrays - array(array('a' => 1, 'b' => 2), array('b' => 2, 'a' => 1)), - array(array(1), array('1')), - array(array(3, 2, 1), array(2, 3, 1), 0, TRUE), // canonicalized comparison - // floats - array(2.3, 2.5, 0.5), - array(array(2.3), array(2.5), 0.5), - array(array(array(2.3)), array(array(2.5)), 0.5), - array(new Struct(2.3), new Struct(2.5), 0.5), - array(array(new Struct(2.3)), array(new Struct(2.5)), 0.5), - // numeric with delta - array(1, 2, 1), - // objects - array($object1, $object2), - array($book1, $book2), - // SplObjectStorage - array($storage1, $storage2), - // DOMDocument - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument(''), - $this->createDOMDocument(''), - ), - array( - $this->createDOMDocument("\n \n"), - $this->createDOMDocument(''), - ), - // Exception - //array(new Exception('Exception 1'), new Exception('Exception 1')), - // mixed types - array(0, '0'), - array('0', 0), - array(2.3, '2.3'), - array('2.3', 2.3), - array((string)(1/3), 1 - 2/3), - array(1/3, (string)(1 - 2/3)), - array('string representation', new ClassWithToString), - array(new ClassWithToString, 'string representation'), - ); - } - - public function equalProvider() - { - // same |= equal - return array_merge($this->equalValues(), $this->sameValues()); - } - - public function notEqualProvider() - { - return $this->notEqualValues(); - } - - public function sameProvider() - { - return $this->sameValues(); - } - - public function notSameProvider() - { - // not equal |= not same - // equal, ¬same |= not same - return array_merge($this->notEqualValues(), $this->equalValues()); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEquals - * @dataProvider equalProvider - */ - public function testAssertEqualsSucceeds($a, $b, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - $this->assertEquals($a, $b, '', $delta, 10, $canonicalize, $ignoreCase); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEquals - * @dataProvider notEqualProvider - */ - public function testAssertEqualsFails($a, $b, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - try { - $this->assertEquals($a, $b, '', $delta, 10, $canonicalize, $ignoreCase); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotEquals - * @dataProvider notEqualProvider - */ - public function testAssertNotEqualsSucceeds($a, $b, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - $this->assertNotEquals($a, $b, '', $delta, 10, $canonicalize, $ignoreCase); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotEquals - * @dataProvider equalProvider - */ - public function testAssertNotEqualsFails($a, $b, $delta = 0, $canonicalize = FALSE, $ignoreCase = FALSE) - { - try { - $this->assertNotEquals($a, $b, '', $delta, 10, $canonicalize, $ignoreCase); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSame - * @dataProvider sameProvider - */ - public function testAssertSameSucceeds($a, $b) - { - $this->assertSame($a, $b); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSame - * @dataProvider notSameProvider - */ - public function testAssertSameFails($a, $b) - { - try { - $this->assertSame($a, $b); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotSame - * @dataProvider notSameProvider - */ - public function testAssertNotSameSucceeds($a, $b) - { - $this->assertNotSame($a, $b); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotSame - * @dataProvider sameProvider - */ - public function testAssertNotSameFails($a, $b) - { - try { - $this->assertNotSame($a, $b); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlFileEqualsXmlFile - */ - public function testAssertXmlFileEqualsXmlFile() - { - $this->assertXmlFileEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'foo.xml' - ); - - try { - $this->assertXmlFileEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'bar.xml' - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlFileNotEqualsXmlFile - */ - public function testAssertXmlFileNotEqualsXmlFile() - { - $this->assertXmlFileNotEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'bar.xml' - ); - - try { - $this->assertXmlFileNotEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'foo.xml' - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlStringEqualsXmlFile - */ - public function testAssertXmlStringEqualsXmlFile() - { - $this->assertXmlStringEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'foo.xml') - ); - - try { - $this->assertXmlStringEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'bar.xml') - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlFile - */ - public function testXmlStringNotEqualsXmlFile() - { - $this->assertXmlStringNotEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'bar.xml') - ); - - try { - $this->assertXmlStringNotEqualsXmlFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'foo.xml') - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlStringEqualsXmlString - */ - public function testAssertXmlStringEqualsXmlString() - { - $this->assertXmlStringEqualsXmlString('', ''); - - try { - $this->assertXmlStringEqualsXmlString('', ''); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertXmlStringNotEqualsXmlString - */ - public function testAssertXmlStringNotEqualsXmlString() - { - $this->assertXmlStringNotEqualsXmlString('', ''); - - try { - $this->assertXmlStringNotEqualsXmlString('', ''); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - */ - public function testXMLStructureIsSame() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureExpected.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - * @expectedException PHPUnit_Framework_ExpectationFailedException - */ - public function testXMLStructureWrongNumberOfAttributes() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureWrongNumberOfAttributes.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - * @expectedException PHPUnit_Framework_ExpectationFailedException - */ - public function testXMLStructureWrongNumberOfNodes() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureWrongNumberOfNodes.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - */ - public function testXMLStructureIsSameButDataIsNot() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureIsSameButDataIsNot.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - */ - public function testXMLStructureAttributesAreSameButValuesAreNot() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureAttributesAreSameButValuesAreNot.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEqualXMLStructure - */ - public function testXMLStructureIgnoreTextNodes() - { - $expected = new DOMDocument; - $expected->load($this->filesDirectory . 'structureExpected.xml'); - - $actual = new DOMDocument; - $actual->load($this->filesDirectory . 'structureIgnoreTextNodes.xml'); - - $this->assertEqualXMLStructure( - $expected->firstChild, $actual->firstChild, TRUE - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEquals - */ - public function testAssertStringEqualsNumeric() - { - $this->assertEquals('0', 0); - - try { - $this->assertEquals('0', 1); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotEquals - */ - public function testAssertStringEqualsNumeric2() - { - $this->assertNotEquals('A', 0); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileExists - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertFileExistsThrowsException() - { - $this->assertFileExists(NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileExists - */ - public function testAssertFileExists() - { - $this->assertFileExists(__FILE__); - - try { - $this->assertFileExists(__DIR__ . DIRECTORY_SEPARATOR . 'NotExisting'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileNotExists - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertFileNotExistsThrowsException() - { - $this->assertFileNotExists(NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileNotExists - */ - public function testAssertFileNotExists() - { - $this->assertFileNotExists(__DIR__ . DIRECTORY_SEPARATOR . 'NotExisting'); - - try { - $this->assertFileNotExists(__FILE__); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - */ - public function testAssertObjectHasAttribute() - { - $o = new Author('Terry Pratchett'); - - $this->assertObjectHasAttribute('name', $o); - - try { - $this->assertObjectHasAttribute('foo', $o); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - */ - public function testAssertObjectNotHasAttribute() - { - $o = new Author('Terry Pratchett'); - - $this->assertObjectNotHasAttribute('foo', $o); - - try { - $this->assertObjectNotHasAttribute('name', $o); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNull - */ - public function testAssertNull() - { - $this->assertNull(NULL); - - try { - $this->assertNull(new stdClass); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotNull - */ - public function testAssertNotNull() - { - $this->assertNotNull(new stdClass); - - try { - $this->assertNotNull(NULL); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTrue - */ - public function testAssertTrue() - { - $this->assertTrue(TRUE); - - try { - $this->assertTrue(FALSE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFalse - */ - public function testAssertFalse() - { - $this->assertFalse(FALSE); - - try { - $this->assertFalse(TRUE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertRegExp - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertRegExpThrowsException() - { - $this->assertRegExp(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertRegExp - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertRegExpThrowsException2() - { - $this->assertRegExp('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotRegExp - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertNotRegExpThrowsException() - { - $this->assertNotRegExp(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotRegExp - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertNotRegExpThrowsException2() - { - $this->assertNotRegExp('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertRegExp - */ - public function testAssertRegExp() - { - $this->assertRegExp('/foo/', 'foobar'); - - try { - $this->assertRegExp('/foo/', 'bar'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotRegExp - */ - public function testAssertNotRegExp() - { - $this->assertNotRegExp('/foo/', 'bar'); - - try { - $this->assertNotRegExp('/foo/', 'foobar'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSame - */ - public function testAssertSame() - { - $o = new stdClass; - - $this->assertSame($o, $o); - - try { - $this->assertSame( - new stdClass, - new stdClass - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSame - */ - public function testAssertSame2() - { - $this->assertSame(TRUE, TRUE); - $this->assertSame(FALSE, FALSE); - - try { - $this->assertSame(TRUE, FALSE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotSame - */ - public function testAssertNotSame() - { - $this->assertNotSame( - new stdClass, - NULL - ); - - $this->assertNotSame( - NULL, - new stdClass - ); - - $this->assertNotSame( - new stdClass, - new stdClass - ); - - $o = new stdClass; - - try { - $this->assertNotSame($o, $o); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotSame - */ - public function testAssertNotSame2() - { - $this->assertNotSame(TRUE, FALSE); - $this->assertNotSame(FALSE, TRUE); - - try { - $this->assertNotSame(TRUE, TRUE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotSame - */ - public function testAssertNotSameFailsNull() - { - try { - $this->assertNotSame(NULL, NULL); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertGreaterThan - */ - public function testGreaterThan() - { - $this->assertGreaterThan(1, 2); - - try { - $this->assertGreaterThan(2, 1); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeGreaterThan - */ - public function testAttributeGreaterThan() - { - $this->assertAttributeGreaterThan( - 1, 'bar', new ClassWithNonPublicAttributes - ); - - try { - $this->assertAttributeGreaterThan( - 1, 'foo', new ClassWithNonPublicAttributes - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertGreaterThanOrEqual - */ - public function testGreaterThanOrEqual() - { - $this->assertGreaterThanOrEqual(1, 2); - - try { - $this->assertGreaterThanOrEqual(2, 1); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeGreaterThanOrEqual - */ - public function testAttributeGreaterThanOrEqual() - { - $this->assertAttributeGreaterThanOrEqual( - 1, 'bar', new ClassWithNonPublicAttributes - ); - - try { - $this->assertAttributeGreaterThanOrEqual( - 2, 'foo', new ClassWithNonPublicAttributes - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertLessThan - */ - public function testLessThan() - { - $this->assertLessThan(2, 1); - - try { - $this->assertLessThan(1, 2); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeLessThan - */ - public function testAttributeLessThan() - { - $this->assertAttributeLessThan( - 2, 'foo', new ClassWithNonPublicAttributes - ); - - try { - $this->assertAttributeLessThan( - 1, 'bar', new ClassWithNonPublicAttributes - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertLessThanOrEqual - */ - public function testLessThanOrEqual() - { - $this->assertLessThanOrEqual(2, 1); - - try { - $this->assertLessThanOrEqual(1, 2); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeLessThanOrEqual - */ - public function testAttributeLessThanOrEqual() - { - $this->assertAttributeLessThanOrEqual( - 2, 'foo', new ClassWithNonPublicAttributes - ); - - try { - $this->assertAttributeLessThanOrEqual( - 1, 'bar', new ClassWithNonPublicAttributes - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - */ - public function testReadAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertEquals('foo', $this->readAttribute($obj, 'publicAttribute')); - $this->assertEquals('bar', $this->readAttribute($obj, 'protectedAttribute')); - $this->assertEquals('baz', $this->readAttribute($obj, 'privateAttribute')); - $this->assertEquals('bar', $this->readAttribute($obj, 'protectedParentAttribute')); - //$this->assertEquals('bar', $this->readAttribute($obj, 'privateParentAttribute')); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - */ - public function testReadAttribute2() - { - $this->assertEquals('foo', $this->readAttribute('ClassWithNonPublicAttributes', 'publicStaticAttribute')); - $this->assertEquals('bar', $this->readAttribute('ClassWithNonPublicAttributes', 'protectedStaticAttribute')); - $this->assertEquals('baz', $this->readAttribute('ClassWithNonPublicAttributes', 'privateStaticAttribute')); - $this->assertEquals('foo', $this->readAttribute('ClassWithNonPublicAttributes', 'protectedStaticParentAttribute')); - $this->assertEquals('foo', $this->readAttribute('ClassWithNonPublicAttributes', 'privateStaticParentAttribute')); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testReadAttribute3() - { - $this->readAttribute('StdClass', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testReadAttribute4() - { - $this->readAttribute('NotExistingClass', 'foo'); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testReadAttribute5() - { - $this->readAttribute(NULL, 'foo'); - } - - /** - * @covers PHPUnit_Framework_Assert::readAttribute - * @covers PHPUnit_Framework_Assert::getStaticAttribute - * @covers PHPUnit_Framework_Assert::getObjectAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testReadAttributeIfAttributeNameIsNotValid() - { - $this->readAttribute('StdClass', '2'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeContains - */ - public function testAssertPublicAttributeContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeContains('foo', 'publicArray', $obj); - - try { - $this->assertAttributeContains('bar', 'publicArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeContainsOnly - */ - public function testAssertPublicAttributeContainsOnly() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeContainsOnly('string', 'publicArray', $obj); - - try { - $this->assertAttributeContainsOnly('integer', 'publicArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotContains - */ - public function testAssertPublicAttributeNotContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotContains('bar', 'publicArray', $obj); - - try { - $this->assertAttributeNotContains('foo', 'publicArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotContainsOnly - */ - public function testAssertPublicAttributeNotContainsOnly() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotContainsOnly('integer', 'publicArray', $obj); - - try { - $this->assertAttributeNotContainsOnly('string', 'publicArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeContains - */ - public function testAssertProtectedAttributeContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeContains('bar', 'protectedArray', $obj); - - try { - $this->assertAttributeContains('foo', 'protectedArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotContains - */ - public function testAssertProtectedAttributeNotContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotContains('foo', 'protectedArray', $obj); - - try { - $this->assertAttributeNotContains('bar', 'protectedArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeContains - */ - public function testAssertPrivateAttributeContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeContains('baz', 'privateArray', $obj); - - try { - $this->assertAttributeContains('foo', 'privateArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotContains - */ - public function testAssertPrivateAttributeNotContains() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotContains('foo', 'privateArray', $obj); - - try { - $this->assertAttributeNotContains('baz', 'privateArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeContains - */ - public function testAssertAttributeContainsNonObject() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeContains(TRUE, 'privateArray', $obj); - - try { - $this->assertAttributeContains(TRUE, 'privateArray', $obj, '', FALSE, TRUE, TRUE); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotContains - */ - public function testAssertAttributeNotContainsNonObject() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotContains(TRUE, 'privateArray', $obj, '', FALSE, TRUE, TRUE); - - try { - $this->assertAttributeNotContains(TRUE, 'privateArray', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertPublicAttributeEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeEquals('foo', 'publicAttribute', $obj); - - try { - $this->assertAttributeEquals('bar', 'publicAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertPublicAttributeNotEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotEquals('bar', 'publicAttribute', $obj); - - try { - $this->assertAttributeNotEquals('foo', 'publicAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeSame - */ - public function testAssertPublicAttributeSame() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeSame('foo', 'publicAttribute', $obj); - - try { - $this->assertAttributeSame('bar', 'publicAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotSame - */ - public function testAssertPublicAttributeNotSame() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotSame('bar', 'publicAttribute', $obj); - - try { - $this->assertAttributeNotSame('foo', 'publicAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertProtectedAttributeEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeEquals('bar', 'protectedAttribute', $obj); - - try { - $this->assertAttributeEquals('foo', 'protectedAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertProtectedAttributeNotEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotEquals('foo', 'protectedAttribute', $obj); - - try { - $this->assertAttributeNotEquals('bar', 'protectedAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertPrivateAttributeEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeEquals('baz', 'privateAttribute', $obj); - - try { - $this->assertAttributeEquals('foo', 'privateAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertPrivateAttributeNotEquals() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertAttributeNotEquals('foo', 'privateAttribute', $obj); - - try { - $this->assertAttributeNotEquals('baz', 'privateAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertPublicStaticAttributeEquals() - { - $this->assertAttributeEquals('foo', 'publicStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeEquals('bar', 'publicStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertPublicStaticAttributeNotEquals() - { - $this->assertAttributeNotEquals('bar', 'publicStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeNotEquals('foo', 'publicStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertProtectedStaticAttributeEquals() - { - $this->assertAttributeEquals('bar', 'protectedStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeEquals('foo', 'protectedStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertProtectedStaticAttributeNotEquals() - { - $this->assertAttributeNotEquals('foo', 'protectedStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeNotEquals('bar', 'protectedStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEquals - */ - public function testAssertPrivateStaticAttributeEquals() - { - $this->assertAttributeEquals('baz', 'privateStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeEquals('foo', 'privateStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEquals - */ - public function testAssertPrivateStaticAttributeNotEquals() - { - $this->assertAttributeNotEquals('foo', 'privateStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertAttributeNotEquals('baz', 'privateStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasAttributeThrowsException() - { - $this->assertClassHasAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasAttributeThrowsException2() - { - $this->assertClassHasAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertClassHasAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasAttributeThrowsException() - { - $this->assertClassNotHasAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasAttributeThrowsException2() - { - $this->assertClassNotHasAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertClassNotHasAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasStaticAttributeThrowsException() - { - $this->assertClassHasStaticAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasStaticAttributeThrowsException2() - { - $this->assertClassHasStaticAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassHasStaticAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertClassHasStaticAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasStaticAttributeThrowsException() - { - $this->assertClassNotHasStaticAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasStaticAttributeThrowsException2() - { - $this->assertClassNotHasStaticAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertClassNotHasStaticAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertClassNotHasStaticAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectHasAttributeThrowsException() - { - $this->assertObjectHasAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectHasAttributeThrowsException2() - { - $this->assertObjectHasAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectHasAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertObjectHasAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectNotHasAttributeThrowsException() - { - $this->assertObjectNotHasAttribute(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectNotHasAttributeThrowsException2() - { - $this->assertObjectNotHasAttribute('foo', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertObjectNotHasAttributeThrowsExceptionIfAttributeNameIsNotValid() - { - $this->assertObjectNotHasAttribute('1', 'ClassWithNonPublicAttributes'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasAttribute - */ - public function testClassHasPublicAttribute() - { - $this->assertClassHasAttribute('publicAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertClassHasAttribute('attribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasAttribute - */ - public function testClassNotHasPublicAttribute() - { - $this->assertClassNotHasAttribute('attribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertClassNotHasAttribute('publicAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassHasStaticAttribute - */ - public function testClassHasPublicStaticAttribute() - { - $this->assertClassHasStaticAttribute('publicStaticAttribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertClassHasStaticAttribute('attribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertClassNotHasStaticAttribute - */ - public function testClassNotHasPublicStaticAttribute() - { - $this->assertClassNotHasStaticAttribute('attribute', 'ClassWithNonPublicAttributes'); - - try { - $this->assertClassNotHasStaticAttribute('publicStaticAttribute', 'ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - */ - public function testObjectHasPublicAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectHasAttribute('publicAttribute', $obj); - - try { - $this->assertObjectHasAttribute('attribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - */ - public function testObjectNotHasPublicAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectNotHasAttribute('attribute', $obj); - - try { - $this->assertObjectNotHasAttribute('publicAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - */ - public function testObjectHasOnTheFlyAttribute() - { - $obj = new StdClass; - $obj->foo = 'bar'; - - $this->assertObjectHasAttribute('foo', $obj); - - try { - $this->assertObjectHasAttribute('bar', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - */ - public function testObjectNotHasOnTheFlyAttribute() - { - $obj = new StdClass; - $obj->foo = 'bar'; - - $this->assertObjectNotHasAttribute('bar', $obj); - - try { - $this->assertObjectNotHasAttribute('foo', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - */ - public function testObjectHasProtectedAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectHasAttribute('protectedAttribute', $obj); - - try { - $this->assertObjectHasAttribute('attribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - */ - public function testObjectNotHasProtectedAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectNotHasAttribute('attribute', $obj); - - try { - $this->assertObjectNotHasAttribute('protectedAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectHasAttribute - */ - public function testObjectHasPrivateAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectHasAttribute('privateAttribute', $obj); - - try { - $this->assertObjectHasAttribute('attribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertObjectNotHasAttribute - */ - public function testObjectNotHasPrivateAttribute() - { - $obj = new ClassWithNonPublicAttributes; - - $this->assertObjectNotHasAttribute('attribute', $obj); - - try { - $this->assertObjectNotHasAttribute('privateAttribute', $obj); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::attribute - * @covers PHPUnit_Framework_Assert::equalTo - */ - public function testAssertThatAttributeEquals() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->attribute( - $this->equalTo('foo'), - 'publicAttribute' - ) - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::attribute - * @covers PHPUnit_Framework_Assert::equalTo - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertThatAttributeEquals2() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->attribute( - $this->equalTo('bar'), - 'publicAttribute' - ) - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::attribute - * @covers PHPUnit_Framework_Assert::equalTo - */ - public function testAssertThatAttributeEqualTo() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->attributeEqualTo('publicAttribute', 'foo') - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::anything - */ - public function testAssertThatAnything() - { - $this->assertThat('anything', $this->anything()); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::anything - * @covers PHPUnit_Framework_Assert::logicalAnd - */ - public function testAssertThatAnythingAndAnything() - { - $this->assertThat( - 'anything', - $this->logicalAnd( - $this->anything(), $this->anything() - ) - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::anything - * @covers PHPUnit_Framework_Assert::logicalOr - */ - public function testAssertThatAnythingOrAnything() - { - $this->assertThat( - 'anything', - $this->logicalOr( - $this->anything(), $this->anything() - ) - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::anything - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Assert::logicalXor - */ - public function testAssertThatAnythingXorNotAnything() - { - $this->assertThat( - 'anything', - $this->logicalXor( - $this->anything(), - $this->logicalNot($this->anything()) - ) - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::contains - */ - public function testAssertThatContains() - { - $this->assertThat(array('foo'), $this->contains('foo')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::stringContains - */ - public function testAssertThatStringContains() - { - $this->assertThat('barfoobar', $this->stringContains('foo')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::containsOnly - */ - public function testAssertThatContainsOnly() - { - $this->assertThat(array('foo'), $this->containsOnly('string')); - } - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::containsOnlyInstancesOf - */ - public function testAssertThatContainsOnlyInstancesOf() - { - $this->assertThat(array(new Book), $this->containsOnlyInstancesOf('Book')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::arrayHasKey - */ - public function testAssertThatArrayHasKey() - { - $this->assertThat(array('foo' => 'bar'), $this->arrayHasKey('foo')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::classHasAttribute - */ - public function testAssertThatClassHasAttribute() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->classHasAttribute('publicAttribute') - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::classHasStaticAttribute - */ - public function testAssertThatClassHasStaticAttribute() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->classHasStaticAttribute('publicStaticAttribute') - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::objectHasAttribute - */ - public function testAssertThatObjectHasAttribute() - { - $this->assertThat( - new ClassWithNonPublicAttributes, - $this->objectHasAttribute('publicAttribute') - ); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::equalTo - */ - public function testAssertThatEqualTo() - { - $this->assertThat('foo', $this->equalTo('foo')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::identicalTo - */ - public function testAssertThatIdenticalTo() - { - $value = new StdClass; - $constraint = $this->identicalTo($value); - - $this->assertThat($value, $constraint); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::isInstanceOf - */ - public function testAssertThatIsInstanceOf() - { - $this->assertThat(new StdClass, $this->isInstanceOf('StdClass')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::isType - */ - public function testAssertThatIsType() - { - $this->assertThat('string', $this->isType('string')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::fileExists - */ - public function testAssertThatFileExists() - { - $this->assertThat(__FILE__, $this->fileExists()); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::greaterThan - */ - public function testAssertThatGreaterThan() - { - $this->assertThat(2, $this->greaterThan(1)); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::greaterThanOrEqual - */ - public function testAssertThatGreaterThanOrEqual() - { - $this->assertThat(2, $this->greaterThanOrEqual(1)); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::lessThan - */ - public function testAssertThatLessThan() - { - $this->assertThat(1, $this->lessThan(2)); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::lessThanOrEqual - */ - public function testAssertThatLessThanOrEqual() - { - $this->assertThat(1, $this->lessThanOrEqual(2)); - } - - /** - * @covers PHPUnit_Framework_Assert::assertThat - * @covers PHPUnit_Framework_Assert::matchesRegularExpression - */ - public function testAssertThatMatchesRegularExpression() - { - $this->assertThat('foobar', $this->matchesRegularExpression('/foo/')); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagTypeTrue() - { - $matcher = array('tag' => 'html'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagTypeFalse() - { - $matcher = array('tag' => 'code'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagIdTrue() - { - $matcher = array('id' => 'test_text'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagIdFalse() - { - $matcher = array('id' => 'test_text_doesnt_exist'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagStringContentTrue() - { - $matcher = array('id' => 'test_text', - 'content' => 'My test tag content'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagStringContentFalse() - { - $matcher = array('id' => 'test_text', - 'content' => 'My non existent tag content'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagRegexpContentTrue() - { - $matcher = array('id' => 'test_text', - 'content' => 'regexp:/test tag/'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagRegexpModifierContentTrue() - { - $matcher = array('id' => 'test_text', - 'content' => 'regexp:/TEST TAG/i'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagRegexpContentFalse() - { - $matcher = array('id' => 'test_text', - 'content' => 'regexp:/asdf/'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagCdataContentTrue() - { - $matcher = array('tag' => 'script', - 'content' => 'alert(\'Hello, world!\');'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagCdataontentFalse() - { - $matcher = array('tag' => 'script', - 'content' => 'asdf'); - $this->assertTag($matcher, $this->html); - } - - - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesTrueA() - { - $matcher = array('tag' => 'span', - 'attributes' => array('class' => 'test_class')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesTrueB() - { - $matcher = array('tag' => 'div', - 'attributes' => array('id' => 'test_child_id')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagAttributesFalse() - { - $matcher = array('tag' => 'span', - 'attributes' => array('class' => 'test_missing_class')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesRegexpTrueA() - { - $matcher = array('tag' => 'span', - 'attributes' => array('class' => 'regexp:/.+_class/')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesRegexpTrueB() - { - $matcher = array('tag' => 'div', - 'attributes' => array('id' => 'regexp:/.+_child_.+/')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesRegexpModifierTrue() - { - $matcher = array('tag' => 'div', - 'attributes' => array('id' => 'regexp:/.+_CHILD_.+/i')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagAttributesRegexpModifierFalse() - { - $matcher = array('tag' => 'div', - 'attributes' => array('id' => 'regexp:/.+_CHILD_.+/')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagAttributesRegexpFalse() - { - $matcher = array('tag' => 'span', - 'attributes' => array('class' => 'regexp:/.+_missing_.+/')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesMultiPartClassTrueA() - { - $matcher = array('tag' => 'div', - 'id' => 'test_multi_class', - 'attributes' => array('class' => 'multi class')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAttributesMultiPartClassTrueB() - { - $matcher = array('tag' => 'div', - 'id' => 'test_multi_class', - 'attributes' => array('class' => 'multi')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagAttributesMultiPartClassFalse() - { - $matcher = array('tag' => 'div', - 'id' => 'test_multi_class', - 'attributes' => array('class' => 'mul')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagParentTrue() - { - $matcher = array('tag' => 'head', - 'parent' => array('tag' => 'html')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagParentFalse() - { - $matcher = array('tag' => 'head', - 'parent' => array('tag' => 'div')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagMultiplePossibleChildren() - { - $matcher = array( - 'tag' => 'li', - 'parent' => array( - 'tag' => 'ul', - 'id' => 'another_ul' - ) - ); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagChildTrue() - { - $matcher = array('tag' => 'html', - 'child' => array('tag' => 'head')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagChildFalse() - { - $matcher = array('tag' => 'html', - 'child' => array('tag' => 'div')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagAncestorTrue() - { - $matcher = array('tag' => 'div', - 'ancestor' => array('tag' => 'html')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagAncestorFalse() - { - $matcher = array('tag' => 'html', - 'ancestor' => array('tag' => 'div')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagDescendantTrue() - { - $matcher = array('tag' => 'html', - 'descendant' => array('tag' => 'div')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagDescendantFalse() - { - $matcher = array('tag' => 'div', - 'descendant' => array('tag' => 'html')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagChildrenCountTrue() - { - $matcher = array('tag' => 'ul', - 'children' => array('count' => 3)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagChildrenCountFalse() - { - $matcher = array('tag' => 'ul', - 'children' => array('count' => 5)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagChildrenLessThanTrue() - { - $matcher = array('tag' => 'ul', - 'children' => array('less_than' => 10)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagChildrenLessThanFalse() - { - $matcher = array('tag' => 'ul', - 'children' => array('less_than' => 2)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagChildrenGreaterThanTrue() - { - $matcher = array('tag' => 'ul', - 'children' => array('greater_than' => 2)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagChildrenGreaterThanFalse() - { - $matcher = array('tag' => 'ul', - 'children' => array('greater_than' => 10)); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagChildrenOnlyTrue() - { - $matcher = array('tag' => 'ul', - 'children' => array('only' => array('tag' =>'li'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagChildrenOnlyFalse() - { - $matcher = array('tag' => 'ul', - 'children' => array('only' => array('tag' =>'div'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagTypeIdTrueA() - { - $matcher = array('tag' => 'ul', 'id' => 'my_ul'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagTypeIdTrueB() - { - $matcher = array('id' => 'my_ul', 'tag' => 'ul'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagTypeIdTrueC() - { - $matcher = array('tag' => 'input', 'id' => 'input_test_id'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertTagTypeIdFalse() - { - $matcher = array('tag' => 'div', 'id' => 'my_ul'); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertTagContentAttributes() - { - $matcher = array('tag' => 'div', - 'content' => 'Test Id Text', - 'attributes' => array('id' => 'test_id', - 'class' => 'my_test_class')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertParentContentAttributes() - { - $matcher = array('tag' => 'div', - 'content' => 'Test Id Text', - 'attributes' => array('id' => 'test_id', - 'class' => 'my_test_class'), - 'parent' => array('tag' => 'body')); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertChildContentAttributes() - { - $matcher = array('tag' => 'div', - 'content' => 'Test Id Text', - 'attributes' => array('id' => 'test_id', - 'class' => 'my_test_class'), - 'child' => array('tag' => 'div', - 'attributes' => array('id' => 'test_child_id'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertChildSubChildren() - { - $matcher = array('id' => 'test_id', - 'child' => array('id' => 'test_child_id', - 'child' => array('id' => 'test_subchild_id'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertAncestorContentAttributes() - { - $matcher = array('id' => 'test_subchild_id', - 'content' => 'My Subchild', - 'attributes' => array('id' => 'test_subchild_id'), - 'ancestor' => array('tag' => 'div', - 'attributes' => array('id' => 'test_id'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertDescendantContentAttributes() - { - $matcher = array('id' => 'test_id', - 'content' => 'Test Id Text', - 'attributes' => array('id' => 'test_id'), - 'descendant' => array('tag' => 'span', - 'attributes' => array('id' => 'test_subchild_id'))); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertTag - */ - public function testAssertChildrenContentAttributes() - { - $matcher = array('id' => 'test_children', - 'content' => 'My Children', - 'attributes' => array('class' => 'children'), - - 'children' => array('less_than' => '25', - 'greater_than' => '2', - 'only' => array('tag' => 'div', - 'attributes' => array('class' => 'my_child')) - )); - $this->assertTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotTag - */ - public function testAssertNotTagTypeIdFalse() - { - $matcher = array('tag' => 'div', 'id' => 'my_ul'); - $this->assertNotTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotTag - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertNotTagContentAttributes() - { - $matcher = array('tag' => 'div', - 'content' => 'Test Id Text', - 'attributes' => array('id' => 'test_id', - 'class' => 'my_test_class')); - $this->assertNotTag($matcher, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountPresentTrue() - { - $selector = 'div#test_id'; - $count = TRUE; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountPresentFalse() - { - $selector = 'div#non_existent'; - $count = TRUE; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountNotPresentTrue() - { - $selector = 'div#non_existent'; - $count = FALSE; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectNotPresentFalse() - { - $selector = 'div#test_id'; - $count = FALSE; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountChildTrue() - { - $selector = '#my_ul > li'; - $count = 3; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountChildFalse() - { - $selector = '#my_ul > li'; - $count = 4; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountDescendantTrue() - { - $selector = '#my_ul li'; - $count = 3; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountDescendantFalse() - { - $selector = '#my_ul li'; - $count = 4; - - $this->assertSelectCount($selector, $count, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountGreaterThanTrue() - { - $selector = '#my_ul > li'; - $range = array('>' => 2); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountGreaterThanFalse() - { - $selector = '#my_ul > li'; - $range = array('>' => 3); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountGreaterThanEqualToTrue() - { - $selector = '#my_ul > li'; - $range = array('>=' => 3); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountGreaterThanEqualToFalse() - { - $selector = '#my_ul > li'; - $range = array('>=' => 4); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountLessThanTrue() - { - $selector = '#my_ul > li'; - $range = array('<' => 4); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountLessThanFalse() - { - $selector = '#my_ul > li'; - $range = array('<' => 3); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountLessThanEqualToTrue() - { - $selector = '#my_ul > li'; - $range = array('<=' => 3); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountLessThanEqualToFalse() - { - $selector = '#my_ul > li'; - $range = array('<=' => 2); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - */ - public function testAssertSelectCountRangeTrue() - { - $selector = '#my_ul > li'; - $range = array('>' => 2, '<' => 4); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectCount - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectCountRangeFalse() - { - $selector = '#my_ul > li'; - $range = array('>' => 1, '<' => 3); - - $this->assertSelectCount($selector, $range, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectEquals - */ - public function testAssertSelectEqualsContentPresentTrue() - { - $selector = 'span.test_class'; - $content = 'Test Class Text'; - - $this->assertSelectEquals($selector, $content, TRUE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectEquals - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectEqualsContentPresentFalse() - { - $selector = 'span.test_class'; - $content = 'Test Nonexistent'; - - $this->assertSelectEquals($selector, $content, TRUE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectEquals - */ - public function testAssertSelectEqualsContentNotPresentTrue() - { - $selector = 'span.test_class'; - $content = 'Test Nonexistent'; - - $this->assertSelectEquals($selector, $content, FALSE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectEquals - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertSelectEqualsContentNotPresentFalse() - { - $selector = 'span.test_class'; - $content = 'Test Class Text'; - - $this->assertSelectEquals($selector, $content, FALSE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectRegExp - */ - public function testAssertSelectRegExpContentPresentTrue() - { - $selector = 'span.test_class'; - $regexp = '/Test.*Text/'; - - $this->assertSelectRegExp($selector, $regexp, TRUE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertSelectRegExp - */ - public function testAssertSelectRegExpContentPresentFalse() - { - $selector = 'span.test_class'; - $regexp = '/Nonexistant/'; - - $this->assertSelectRegExp($selector, $regexp, FALSE, $this->html); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileEquals - */ - public function testAssertFileEquals() - { - $this->assertFileEquals( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'foo.xml' - ); - - try { - $this->assertFileEquals( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'bar.xml' - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertFileNotEquals - */ - public function testAssertFileNotEquals() - { - $this->assertFileNotEquals( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'bar.xml' - ); - - try { - $this->assertFileNotEquals( - $this->filesDirectory . 'foo.xml', - $this->filesDirectory . 'foo.xml' - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEqualsFile - */ - public function testAssertStringEqualsFile() - { - $this->assertStringEqualsFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'foo.xml') - ); - - try { - $this->assertStringEqualsFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'bar.xml') - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringNotEqualsFile - */ - public function testAssertStringNotEqualsFile() - { - $this->assertStringNotEqualsFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'bar.xml') - ); - - try { - $this->assertStringNotEqualsFile( - $this->filesDirectory . 'foo.xml', - file_get_contents($this->filesDirectory . 'foo.xml') - ); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringStartsWithThrowsException() - { - $this->assertStringStartsWith(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringStartsWithThrowsException2() - { - $this->assertStringStartsWith('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsNotWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringStartsNotWithThrowsException() - { - $this->assertStringStartsNotWith(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsNotWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringStartsNotWithThrowsException2() - { - $this->assertStringStartsNotWith('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringEndsWithThrowsException() - { - $this->assertStringEndsWith(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringEndsWithThrowsException2() - { - $this->assertStringEndsWith('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsNotWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringEndsNotWithThrowsException() - { - $this->assertStringEndsNotWith(NULL, NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsNotWith - * @expectedException PHPUnit_Framework_Exception - */ - public function testAssertStringEndsNotWithThrowsException2() - { - $this->assertStringEndsNotWith('', NULL); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsWith - */ - public function testAssertStringStartsWith() - { - $this->assertStringStartsWith('prefix', 'prefixfoo'); - - try { - $this->assertStringStartsWith('prefix', 'foo'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringStartsNotWith - */ - public function testAssertStringStartsNotWith() - { - $this->assertStringStartsNotWith('prefix', 'foo'); - - try { - $this->assertStringStartsNotWith('prefix', 'prefixfoo'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsWith - */ - public function testAssertStringEndsWith() - { - $this->assertStringEndsWith('suffix', 'foosuffix'); - - try { - $this->assertStringEndsWith('suffix', 'foo'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringEndsNotWith - */ - public function testAssertStringEndsNotWith() - { - $this->assertStringEndsNotWith('suffix', 'foo'); - - try { - $this->assertStringEndsNotWith('suffix', 'foosuffix'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringMatchesFormat - */ - public function testAssertStringMatchesFormat() - { - $this->assertStringMatchesFormat('*%s*', '***'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringMatchesFormat - * @expectedException PHPUnit_Framework_AssertionFailedError - */ - public function testAssertStringMatchesFormatFailure() - { - $this->assertStringMatchesFormat('*%s*', '**'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertStringNotMatchesFormat - */ - public function testAssertStringNotMatchesFormat() - { - $this->assertStringNotMatchesFormat('*%s*', '**'); - - try { - $this->assertStringMatchesFormat('*%s*', '**'); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertEmpty - */ - public function testAssertEmpty() - { - $this->assertEmpty(array()); - - try { - $this->assertEmpty(array('foo')); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertNotEmpty - */ - public function testAssertNotEmpty() - { - $this->assertNotEmpty(array('foo')); - - try { - $this->assertNotEmpty(array()); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeEmpty - */ - public function testAssertAttributeEmpty() - { - $o = new StdClass; - $o->a = array(); - - $this->assertAttributeEmpty('a', $o); - - try { - $o->a = array('b'); - $this->assertAttributeEmpty('a', $o); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertAttributeNotEmpty - */ - public function testAssertAttributeNotEmpty() - { - $o = new StdClass; - $o->a = array('b'); - - $this->assertAttributeNotEmpty('a', $o); - - try { - $o->a = array(); - $this->assertAttributeNotEmpty('a', $o); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::markTestIncomplete - */ - public function testMarkTestIncomplete() - { - try { - $this->markTestIncomplete('incomplete'); - } - - catch (PHPUnit_Framework_IncompleteTestError $e) { - $this->assertEquals('incomplete', $e->getMessage()); - - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::markTestSkipped - */ - public function testMarkTestSkipped() - { - try { - $this->markTestSkipped('skipped'); - } - - catch (PHPUnit_Framework_SkippedTestError $e) { - $this->assertEquals('skipped', $e->getMessage()); - - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertCount - */ - public function testAssertCount() - { - $this->assertCount(2, array(1,2)); - - try { - $this->assertCount(2, array(1,2,3)); - } - - catch (PHPUnit_Framework_AssertionFailedError $e) { - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertCount - */ - public function testAssertCountThrowsExceptionIfExpectedCountIsNoInteger() - { - - try { - $this->assertCount('a', array()); - } - - catch (PHPUnit_Framework_Exception $e) { - $this->assertEquals('Argument #1 (No Value) of PHPUnit_Framework_Assert::assertCount() must be a integer', $e->getMessage()); - - return; - } - - $this->fail(); - } - - - /** - * @covers PHPUnit_Framework_Assert::assertCount - */ - public function testAssertCountThrowsExceptionIfElementIsNotCountable() - { - - try { - $this->assertCount(2, ''); - } - - catch (PHPUnit_Framework_Exception $e) { - $this->assertEquals('Argument #2 (No Value) of PHPUnit_Framework_Assert::assertCount() must be a countable', $e->getMessage()); - - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringEqualsJsonString - */ - public function testAssertJsonStringEqualsJsonString() - { - $expected = '{"Mascott" : "Tux"}'; - $actual = '{"Mascott" : "Tux"}'; - $message = 'Given Json strings do not match'; - - $this->assertJsonStringEqualsJsonString($expected, $actual, $message); - } - - /** - * @dataProvider validInvalidJsonDataprovider - * @covers PHPUnit_Framework_Assert::assertJsonStringEqualsJsonString - */ - public function testAssertJsonStringEqualsJsonStringErrorRaised($expected, $actual) - { - try { - $this->assertJsonStringEqualsJsonString($expected, $actual); - } catch (PHPUnit_Framework_ExpectationFailedException $e) { - return; - } - $this->fail('Expected exception not found'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonString - */ - public function testAssertJsonStringNotEqualsJsonString() - { - $expected = '{"Mascott" : "Beastie"}'; - $actual = '{"Mascott" : "Tux"}'; - $message = 'Given Json strings do match'; - - $this->assertJsonStringNotEqualsJsonString($expected, $actual, $message); - } - - /** - * @dataProvider validInvalidJsonDataprovider - * @covers PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonString - */ - public function testAssertJsonStringNotEqualsJsonStringErrorRaised($expected, $actual) - { - $this->assertJsonStringNotEqualsJsonString($expected, $actual); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringEqualsJsonFile - */ - public function testAssertJsonStringEqualsJsonFile() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - $actual = json_encode(array("Mascott" => "Tux")); - $message = ''; - $this->assertJsonStringEqualsJsonFile($file, $actual, $message); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringEqualsJsonFile - */ - public function testAssertJsonStringEqualsJsonFileExpectingExpectationFailedException() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - $actual = json_encode(array("Mascott" => "Beastie")); - $message = ''; - try { - $this->assertJsonStringEqualsJsonFile($file, $actual, $message); - } catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - 'Failed asserting that \'{"Mascott":"Beastie"}\' matches JSON string "{"Mascott":"Tux"}".', - $e->getMessage() - ); - return; - } - - $this->fail('Expected Exception not thrown.'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringEqualsJsonFile - */ - public function testAssertJsonStringEqualsJsonFileExpectingException() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - try { - $this->assertJsonStringEqualsJsonFile($file, NULL); - } catch (PHPUnit_Framework_Exception $e) { - return; - } - $this->fail('Expected Exception not thrown.'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonFile - */ - public function testAssertJsonStringNotEqualsJsonFile() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - $actual = json_encode(array("Mascott" => "Beastie")); - $message = ''; - $this->assertJsonStringNotEqualsJsonFile($file, $actual, $message); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonStringNotEqualsJsonFile - */ - public function testAssertJsonStringNotEqualsJsonFileExpectingException() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - try { - $this->assertJsonStringNotEqualsJsonFile($file, NULL); - } catch (PHPUnit_Framework_Exception $e) { - return; - } - $this->fail('Expected exception not found.'); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonFileNotEqualsJsonFile - */ - public function testAssertJsonFileNotEqualsJsonFile() - { - $fileExpected = __DIR__ . '/../_files/JsonData/simpleObject.js'; - $fileActual = __DIR__ . '/../_files/JsonData/arrayObject.js'; - $message = ''; - $this->assertJsonFileNotEqualsJsonFile($fileExpected, $fileActual, $message); - } - - /** - * @covers PHPUnit_Framework_Assert::assertJsonFileEqualsJsonFile - */ - public function testAssertJsonFileEqualsJsonFile() - { - $file = __DIR__ . '/../_files/JsonData/simpleObject.js'; - $message = ''; - $this->assertJsonFileEqualsJsonFile($file, $file, $message); - } - - public static function validInvalidJsonDataprovider() - { - return array( - 'error syntax in expected JSON' => array('{"Mascott"::}', '{"Mascott" : "Tux"}'), - 'error UTF-8 in actual JSON' => array('{"Mascott" : "Tux"}', '{"Mascott" : :}'), - ); - } - -} diff --git a/Tests/Framework/BaseTestListenerTest.php b/Tests/Framework/BaseTestListenerTest.php deleted file mode 100644 index c0b484854e8..00000000000 --- a/Tests/Framework/BaseTestListenerTest.php +++ /dev/null @@ -1,70 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Giorgio Sironi - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.8.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'BaseTestListenerSample.php'; - -/** - * - * - * @package PHPUnit - * @author Giorgio Sironi - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.8.0 - */ -class Framework_BaseTestListenerTest extends PHPUnit_Framework_TestCase -{ - public function testEndEventsAreCounted() - { - $this->result = new PHPUnit_Framework_TestResult; - $listener = new BaseTestListenerSample(); - $this->result->addListener($listener); - $test = new Success; - $test->run($this->result); - - $this->assertEquals(1, $listener->endCount); - } -} diff --git a/Tests/Framework/ComparatorTest.php b/Tests/Framework/ComparatorTest.php deleted file mode 100644 index c5c1dbb9699..00000000000 --- a/Tests/Framework/ComparatorTest.php +++ /dev/null @@ -1,159 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithToString.php'; - -class TestClass {} -class TestClassComparator extends PHPUnit_Framework_Comparator_Object {} - -/** - * - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class Framework_ComparatorTest extends PHPUnit_Framework_TestCase -{ - // Don't use other test methods than ->fail() here, because the testers tested - // here are the foundation for the other test methods - - public function instanceProvider() - { - $tmpfile = tmpfile(); - - return array( - array(NULL, NULL, 'PHPUnit_Framework_Comparator_Scalar'), - array(NULL, TRUE, 'PHPUnit_Framework_Comparator_Scalar'), - array(TRUE, NULL, 'PHPUnit_Framework_Comparator_Scalar'), - array(TRUE, TRUE, 'PHPUnit_Framework_Comparator_Scalar'), - array(FALSE, FALSE, 'PHPUnit_Framework_Comparator_Scalar'), - array(TRUE, FALSE, 'PHPUnit_Framework_Comparator_Scalar'), - array(FALSE, TRUE, 'PHPUnit_Framework_Comparator_Scalar'), - array('', '', 'PHPUnit_Framework_Comparator_Scalar'), - array('0', '0', 'PHPUnit_Framework_Comparator_Numeric'), - array('0', 0, 'PHPUnit_Framework_Comparator_Numeric'), - array(0, '0', 'PHPUnit_Framework_Comparator_Numeric'), - array(0, 0, 'PHPUnit_Framework_Comparator_Numeric'), - array(1.0, 0, 'PHPUnit_Framework_Comparator_Double'), - array(0, 1.0, 'PHPUnit_Framework_Comparator_Double'), - array(1.0, 1.0, 'PHPUnit_Framework_Comparator_Double'), - array(array(1), array(1), 'PHPUnit_Framework_Comparator_Array'), - array($tmpfile, $tmpfile, 'PHPUnit_Framework_Comparator_Resource'), - array(new stdClass, new stdClass, 'PHPUnit_Framework_Comparator_Object'), - array(new SplObjectStorage, new SplObjectStorage, 'PHPUnit_Framework_Comparator_SplObjectStorage'), - array(new Exception, new Exception, 'PHPUnit_Framework_Comparator_Exception'), - array(new DOMDocument, new DOMDocument, 'PHPUnit_Framework_Comparator_DOMDocument'), - // mixed types - array($tmpfile, array(1), 'PHPUnit_Framework_Comparator_Type'), - array(array(1), $tmpfile, 'PHPUnit_Framework_Comparator_Type'), - array($tmpfile, '1', 'PHPUnit_Framework_Comparator_Type'), - array('1', $tmpfile, 'PHPUnit_Framework_Comparator_Type'), - array($tmpfile, new stdClass, 'PHPUnit_Framework_Comparator_Type'), - array(new stdClass, $tmpfile, 'PHPUnit_Framework_Comparator_Type'), - array(new stdClass, array(1), 'PHPUnit_Framework_Comparator_Type'), - array(array(1), new stdClass, 'PHPUnit_Framework_Comparator_Type'), - array(new stdClass, '1', 'PHPUnit_Framework_Comparator_Type'), - array('1', new stdClass, 'PHPUnit_Framework_Comparator_Type'), - array(new ClassWithToString, '1', 'PHPUnit_Framework_Comparator_Scalar'), - array('1', new ClassWithToString, 'PHPUnit_Framework_Comparator_Scalar'), - array(1.0, new stdClass, 'PHPUnit_Framework_Comparator_Type'), - array(new stdClass, 1.0, 'PHPUnit_Framework_Comparator_Type'), - array(1.0, array(1), 'PHPUnit_Framework_Comparator_Type'), - array(array(1), 1.0, 'PHPUnit_Framework_Comparator_Type'), - ); - } - - /** - * @dataProvider instanceProvider - */ - public function testGetInstance($a, $b, $expected) - { - $factory = new PHPUnit_Framework_ComparatorFactory; - - if (get_class($factory->getComparatorFor($a, $b)) != $expected) { - $this->fail(); - } - } - - public function testRegister() - { - $comparator = new TestClassComparator; - - $factory = new PHPUnit_Framework_ComparatorFactory; - $factory->register($comparator); - - $a = new TestClass; - $b = new TestClass; - $expected = 'TestClassComparator'; - - if (get_class($factory->getComparatorFor($a, $b)) != $expected) { - $factory->unregister($comparator); - $this->fail(); - } - - $factory->unregister($comparator); - } - - public function testUnregister() - { - $comparator = new TestClassComparator; - - $factory = new PHPUnit_Framework_ComparatorFactory; - $factory->register($comparator); - $factory->unregister($comparator); - - $a = new TestClass; - $b = new TestClass; - $expected = 'PHPUnit_Framework_Comparator_Object'; - - if (get_class($factory->getComparatorFor($a, $b)) != $expected) { - var_dump(get_class($factory->getComparatorFor($a, $b))); - $this->fail(); - } - } -} diff --git a/Tests/Framework/Constraint/JsonMatches/ErrorMessageProviderTest.php b/Tests/Framework/Constraint/JsonMatches/ErrorMessageProviderTest.php deleted file mode 100644 index 9755ad9a8e7..00000000000 --- a/Tests/Framework/Constraint/JsonMatches/ErrorMessageProviderTest.php +++ /dev/null @@ -1,122 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bastian Feder - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ - -/** - * @package PHPUnit - * @author Bastian Feder - * @copyright 2011-2013 Bastian Feder - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ -class Framework_Constraint_JsonMatches_ErrorMessageProviderTest extends PHPUnit_Framework_TestCase -{ - /** - * @dataProvider translateTypeToPrefixDataprovider - * @covers PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix - */ - public function testTranslatTypeToPrefix($expected, $type) - { - $this->assertEquals( - $expected, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::translateTypeToPrefix($type) - ); - } - - /** - * @dataProvider determineJsonErrorDataprovider - * @covers PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError - */ - public function testDetermineJsonError($expected, $error, $prefix) - { - $this->assertEquals( - $expected, - PHPUnit_Framework_Constraint_JsonMatches_ErrorMessageProvider::determineJsonError( - $error, - $prefix - ) - ); - } - - public static function determineJsonErrorDataprovider() - { - return array( - 'JSON_ERROR_NONE' => array( - NULL, 'json_error_none', '' - ), - 'JSON_ERROR_DEPTH' => array( - 'Maximum stack depth exceeded', 'json_error_depth', '' - ), - 'prefixed JSON_ERROR_DEPTH' => array( - 'TUX: Maximum stack depth exceeded', 'json_error_depth', 'TUX: ' - ), - 'JSON_ERROR_STATE_MISMatch' => array( - 'Underflow or the modes mismatch', 'json_error_state_mismatch', '' - ), - 'JSON_ERROR_CTRL_CHAR' => array( - 'Unexpected control character found', 'json_error_ctrl_char', '' - ), - 'JSON_ERROR_SYNTAX' => array( - 'Syntax error, malformed JSON', 'json_error_syntax', '' - ), - 'JSON_ERROR_UTF8`' => array( - 'Malformed UTF-8 characters, possibly incorrectly encoded', - 'json_error_utf8', - '' - ), - 'Invalid error indicator' => array( - 'Unknown error', 'invalid_error_indicator', '' - ), - ); - } - - public static function translateTypeToPrefixDataprovider() - { - return array( - 'expected' => array('Expected value JSON decode error - ', 'expected'), - 'actual' => array('Actual value JSON decode error - ', 'actual'), - 'default' => array('', ''), - ); - } -} diff --git a/Tests/Framework/Constraint/JsonMatchesTest.php b/Tests/Framework/Constraint/JsonMatchesTest.php deleted file mode 100644 index 6761710b270..00000000000 --- a/Tests/Framework/Constraint/JsonMatchesTest.php +++ /dev/null @@ -1,90 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bastian Feder - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ - -/** - * @package PHPUnit - * @author Bastian Feder - * @copyright 2011 Bastian Feder - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause - * @link http://www.phpunit.de/ - * @since File available since Release 3.7.0 - */ -class Framework_Constraint_JsonMatchesTest extends PHPUnit_Framework_TestCase -{ - - /** - * @dataProvider evaluateDataprovider - * @covers PHPUnit_Framework_Constraint_JsonMatches::evaluate - * @covers PHPUnit_Framework_Constraint_JsonMatches::matches - * @covers PHPUnit_Framework_Constraint_JsonMatches::__construct - * @covers PHPUnit_Framework_Constraint_JsonMatches::getJsonError - */ - public function testEvaluate($expected, $jsonOther, $jsonValue) - { - $constraint = new PHPUnit_Framework_Constraint_JsonMatches($jsonValue); - $this->assertEquals($expected, $constraint->evaluate($jsonOther, '', TRUE)); - } - - /** - * @covers PHPUnit_Framework_Constraint_JsonMatches::toString - */ - public function testToString() - { - $jsonValue = json_encode(array('Mascott' => 'Tux')); - $constraint = new PHPUnit_Framework_Constraint_JsonMatches($jsonValue); - - $this->assertEquals('matches JSON string "' . $jsonValue . '"', $constraint->toString()); - } - - - public static function evaluateDataprovider() - { - return array( - 'valid JSON' => array(TRUE, json_encode(array('Mascott' => 'Tux')), json_encode(array('Mascott' => 'Tux'))), - 'error syntax' => array(FALSE, '{"Mascott"::}', json_encode(array('Mascott' => 'Tux'))), - 'error UTF-8' => array(FALSE, json_encode('\xB1\x31'), json_encode(array('Mascott' => 'Tux'))), - 'invalid JSON in class instantiation' => array(FALSE, json_encode(array('Mascott' => 'Tux')), '{"Mascott"::}'), - ); - } -} diff --git a/Tests/Framework/ConstraintTest.php b/Tests/Framework/ConstraintTest.php deleted file mode 100644 index cdfda2bf7c6..00000000000 --- a/Tests/Framework/ConstraintTest.php +++ /dev/null @@ -1,3560 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithNonPublicAttributes.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'TestIterator.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'DummyException.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.0.0 - */ -class Framework_ConstraintTest extends PHPUnit_Framework_TestCase -{ - /** - * Removes spaces in front of newlines - * - * @param string $string - * @return string - */ - public static function trimnl($string) - { - return preg_replace('/[ ]*\n/', "\n", $string); - } - - /** - * @covers PHPUnit_Framework_Constraint_ArrayHasKey - * @covers PHPUnit_Framework_Assert::arrayHasKey - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayHasKey() - { - $constraint = PHPUnit_Framework_Assert::arrayHasKey(0); - - $this->assertFalse($constraint->evaluate(array(), '', TRUE)); - $this->assertEquals('has the key 0', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(array()); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ArrayHasKey - * @covers PHPUnit_Framework_Assert::arrayHasKey - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayHasKey2() - { - $constraint = PHPUnit_Framework_Assert::arrayHasKey(0); - - try { - $constraint->evaluate(array(), 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ArrayHasKey - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::arrayHasKey - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayNotHasKey() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::arrayHasKey(0) - ); - - $this->assertFalse($constraint->evaluate(array(0 => 1), '', TRUE)); - $this->assertEquals('does not have the key 0', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(array(0 => 1)); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ArrayHasKey - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::arrayHasKey - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayNotHasKey2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::arrayHasKey(0) - ); - - try { - $constraint->evaluate(array(0), 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_FileExists - * @covers PHPUnit_Framework_Assert::fileExists - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintFileExists() - { - $constraint = PHPUnit_Framework_Assert::fileExists(); - - $this->assertFalse($constraint->evaluate('foo', '', TRUE)); - $this->assertEquals('file exists', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('foo'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_FileExists - * @covers PHPUnit_Framework_Assert::fileExists - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintFileExists2() - { - $constraint = PHPUnit_Framework_Assert::fileExists(); - - try { - $constraint->evaluate('foo', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_FileExists - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Assert::fileExists - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintFileNotExists() - { - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithNonPublicAttributes.php'; - - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::fileExists() - ); - - $this->assertFalse($constraint->evaluate($file, '', TRUE)); - $this->assertEquals('file does not exist', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate($file); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_FileExists - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Assert::fileExists - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintFileNotExists2() - { - $file = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ClassWithNonPublicAttributes.php'; - - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::fileExists() - ); - - try { - $constraint->evaluate($file, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Assert::greaterThan - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintGreaterThan() - { - $constraint = PHPUnit_Framework_Assert::greaterThan(1); - - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertTrue($constraint->evaluate(2, '', TRUE)); - $this->assertEquals('is greater than 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(0); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Assert::greaterThan - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintGreaterThan2() - { - $constraint = PHPUnit_Framework_Assert::greaterThan(1); - - try { - $constraint->evaluate(0, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::greaterThan - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotGreaterThan() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::greaterThan(1) - ); - - $this->assertTrue($constraint->evaluate(1, '', TRUE)); - $this->assertEquals('is not greater than 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(2); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::greaterThan - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotGreaterThan2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::greaterThan(1) - ); - - try { - $constraint->evaluate(2, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Assert::greaterThanOrEqual - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintGreaterThanOrEqual() - { - $constraint = PHPUnit_Framework_Assert::greaterThanOrEqual(1); - - $this->assertTrue($constraint->evaluate(1, '', TRUE)); - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertEquals('is equal to 1 or is greater than 1', $constraint->toString()); - $this->assertEquals(2, count($constraint)); - - try { - $constraint->evaluate(0); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Assert::greaterThanOrEqual - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintGreaterThanOrEqual2() - { - $constraint = PHPUnit_Framework_Assert::greaterThanOrEqual(1); - - try { - $constraint->evaluate(0, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::greaterThanOrEqual - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotGreaterThanOrEqual() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::greaterThanOrEqual(1) - ); - - $this->assertFalse($constraint->evaluate(1, '', TRUE)); - $this->assertEquals('not( is equal to 1 or is greater than 1 )', $constraint->toString()); - $this->assertEquals(2, count($constraint)); - - try { - $constraint->evaluate(1); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_GreaterThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::greaterThanOrEqual - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotGreaterThanOrEqual2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::greaterThanOrEqual(1) - ); - - try { - $constraint->evaluate(1, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsAnything - * @covers PHPUnit_Framework_Assert::anything - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsAnything() - { - $constraint = PHPUnit_Framework_Assert::anything(); - - $this->assertTrue($constraint->evaluate(NULL, '', TRUE)); - $this->assertNull($constraint->evaluate(NULL)); - $this->assertEquals('is anything', $constraint->toString()); - $this->assertEquals(0, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsAnything - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::anything - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotIsAnything() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::anything() - ); - - $this->assertFalse($constraint->evaluate(NULL, '', TRUE)); - $this->assertEquals('is not anything', $constraint->toString()); - $this->assertEquals(0, count($constraint)); - - try { - $constraint->evaluate(NULL); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Assert::equalTo - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsEqual() - { - $constraint = PHPUnit_Framework_Assert::equalTo(1); - - $this->assertTrue($constraint->evaluate(1, '', TRUE)); - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertEquals('is equal to 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(0); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - public function isEqualProvider() - { - $a = new stdClass; - $a->foo = 'bar'; - $b = new stdClass; - $ahash = spl_object_hash($a); - $bhash = spl_object_hash($b); - - $c = new stdClass; - $c->foo = 'bar'; - $c->int = 1; - $c->array = array(0, array(1), array(2), 3); - $c->related = new stdClass; - $c->related->foo = "a\nb\nc\nd\ne\nf\ng\nh\ni\nj\nk"; - $c->self = $c; - $c->c = $c; - $d = new stdClass; - $d->foo = 'bar'; - $d->int = 2; - $d->array = array(0, array(4), array(2), 3); - $d->related = new stdClass; - $d->related->foo = "a\np\nc\nd\ne\nf\ng\nh\ni\nw\nk"; - $d->self = $d; - $d->c = $c; - - $storage1 = new SplObjectStorage; - $storage1->attach($a); - $storage1->attach($b); - $storage2 = new SplObjectStorage; - $storage2->attach($b); - $storage1hash = spl_object_hash($storage1); - $storage2hash = spl_object_hash($storage2); - - $dom1 = new DOMDocument; - $dom1->preserveWhiteSpace = FALSE; - $dom1->loadXML(''); - $dom2 = new DOMDocument; - $dom2->preserveWhiteSpace = FALSE; - $dom2->loadXML(''); - - return array( - array(1, 0, << 0 -+ 0 => 1 - ) - -EOF - ), - array(array(TRUE), array('true'), << true -+ 0 => 'true' - ) - -EOF - ), - array(array(0, array(1), array(2), 3), array(0, array(4), array(2), 3), << 0 - 1 => Array ( -- 0 => 1 -+ 0 => 4 - ) - 2 => Array (...) - 3 => 3 - ) - -EOF - ), - array($a, array(0), << 'bar' - ) - -EOF - ), - array($c, $d, << 'bar' -- 'int' => 1 -+ 'int' => 2 - 'array' => Array ( - 0 => 0 - 1 => Array ( -- 0 => 1 -+ 0 => 4 - -@@ @@ - 'foo' => 'a -- b -+ p - -@@ @@ - i -- j -+ w - k' - ) - 'self' => stdClass Object (...) - 'c' => stdClass Object (...) - ) - -EOF - ), - array($storage1, $storage2, << Array &0 ( -- 'obj' => stdClass Object &$ahash ( -- 'foo' => 'bar' -- ) -+SplObjectStorage Object &$storage2hash ( -+ '$bhash' => Array &0 ( -+ 'obj' => stdClass Object &$bhash () - 'inf' => null - ) -- '$bhash' => Array &0 - ) - -EOF - ), - array($dom1, $dom2, << -- -+ -+ -+ - -EOF - ), - ); - } - - /** - * @dataProvider isEqualProvider - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Assert::equalTo - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsEqual2($expected, $actual, $message) - { - $constraint = PHPUnit_Framework_Assert::equalTo($expected); - - try { - $constraint->evaluate($actual, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - "custom message\n$message", - self::trimnl(PHPUnit_Framework_TestFailure::exceptionToString($e)) - ); - - return; - } - - $this->fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::equalTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotEqual() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::equalTo(1) - ); - - $this->assertTrue($constraint->evaluate(0, '', TRUE)); - $this->assertFalse($constraint->evaluate(1, '', TRUE)); - $this->assertEquals('is not equal to 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(1); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::equalTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotEqual2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::equalTo(1) - ); - - try { - $constraint->evaluate(1, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsIdentical() - { - $a = new stdClass; - $b = new stdClass; - - $constraint = PHPUnit_Framework_Assert::identicalTo($a); - - $this->assertFalse($constraint->evaluate($b, '', TRUE)); - $this->assertTrue($constraint->evaluate($a, '', TRUE)); - $this->assertEquals('is identical to an object of class "stdClass"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate($b); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsIdentical2() - { - $a = new stdClass; - $b = new stdClass; - - $constraint = PHPUnit_Framework_Assert::identicalTo($a); - - try { - $constraint->evaluate($b, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsIdentical3() - { - $constraint = PHPUnit_Framework_Assert::identicalTo('a'); - - try { - $constraint->evaluate('b', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotIdentical() - { - $a = new stdClass; - $b = new stdClass; - - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::identicalTo($a) - ); - - $this->assertTrue($constraint->evaluate($b, '', TRUE)); - $this->assertFalse($constraint->evaluate($a, '', TRUE)); - $this->assertEquals('is not identical to an object of class "stdClass"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate($a); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotIdentical2() - { - $a = new stdClass; - - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::identicalTo($a) - ); - - try { - $constraint->evaluate($a, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsIdentical - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::identicalTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotIdentical3() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::identicalTo('a') - ); - - try { - $constraint->evaluate('a', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsInstanceOf - * @covers PHPUnit_Framework_Assert::isInstanceOf - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsInstanceOf() - { - $constraint = PHPUnit_Framework_Assert::isInstanceOf('Exception'); - - $this->assertFalse($constraint->evaluate(new stdClass, '', TRUE)); - $this->assertTrue($constraint->evaluate(new Exception, '', TRUE)); - $this->assertEquals('is instance of class "Exception"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - $interfaceConstraint = PHPUnit_Framework_Assert::isInstanceOf('Countable'); - $this->assertFalse($interfaceConstraint->evaluate(new stdClass, '', TRUE)); - $this->assertTrue($interfaceConstraint->evaluate(new ArrayObject, '', TRUE)); - $this->assertEquals('is instance of interface "Countable"', $interfaceConstraint->toString()); - - try { - $constraint->evaluate(new stdClass); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsInstanceOf - * @covers PHPUnit_Framework_Assert::isInstanceOf - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsInstanceOf2() - { - $constraint = PHPUnit_Framework_Assert::isInstanceOf('Exception'); - - try { - $constraint->evaluate(new stdClass, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsInstanceOf - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isInstanceOf - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotInstanceOf() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isInstanceOf('stdClass') - ); - - $this->assertFalse($constraint->evaluate(new stdClass, '', TRUE)); - $this->assertTrue($constraint->evaluate(new Exception, '', TRUE)); - $this->assertEquals('is not instance of class "stdClass"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(new stdClass); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsInstanceOf - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isInstanceOf - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotInstanceOf2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isInstanceOf('stdClass') - ); - - try { - $constraint->evaluate(new stdClass, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsType - * @covers PHPUnit_Framework_Assert::isType - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsType() - { - $constraint = PHPUnit_Framework_Assert::isType('string'); - - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertTrue($constraint->evaluate('', '', TRUE)); - $this->assertEquals('is of type "string"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(new stdClass); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertStringMatchesFormat(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsType - * @covers PHPUnit_Framework_Assert::isType - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsType2() - { - $constraint = PHPUnit_Framework_Assert::isType('string'); - - try { - $constraint->evaluate(new stdClass, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertStringMatchesFormat(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsType - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isType - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotType() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isType('string') - ); - - $this->assertTrue($constraint->evaluate(0, '', TRUE)); - $this->assertFalse($constraint->evaluate('', '', TRUE)); - $this->assertEquals('is not of type "string"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(''); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsType - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isType - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotType2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isType('string') - ); - - try { - $constraint->evaluate('', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsNull - * @covers PHPUnit_Framework_Assert::isNull - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNull() - { - $constraint = PHPUnit_Framework_Assert::isNull(); - - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertTrue($constraint->evaluate(NULL, '', TRUE)); - $this->assertEquals('is null', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(0); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsNull - * @covers PHPUnit_Framework_Assert::isNull - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNull2() - { - $constraint = PHPUnit_Framework_Assert::isNull(); - - try { - $constraint->evaluate(0, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsNull - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isNull - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotNull() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isNull() - ); - - $this->assertFalse($constraint->evaluate(NULL, '', TRUE)); - $this->assertTrue($constraint->evaluate(0, '', TRUE)); - $this->assertEquals('is not null', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(NULL); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsNull - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::isNull - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsNotNull2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::isNull() - ); - - try { - $constraint->evaluate(NULL, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Assert::lessThan - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintLessThan() - { - $constraint = PHPUnit_Framework_Assert::lessThan(1); - - $this->assertTrue($constraint->evaluate(0, '', TRUE)); - $this->assertFalse($constraint->evaluate(1, '', TRUE)); - $this->assertEquals('is less than 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(1); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Assert::lessThan - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintLessThan2() - { - $constraint = PHPUnit_Framework_Assert::lessThan(1); - - try { - $constraint->evaluate(1, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::lessThan - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotLessThan() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::lessThan(1) - ); - - $this->assertTrue($constraint->evaluate(1, '', TRUE)); - $this->assertFalse($constraint->evaluate(0, '', TRUE)); - $this->assertEquals('is not less than 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(0); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::lessThan - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotLessThan2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::lessThan(1) - ); - - try { - $constraint->evaluate(0, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Assert::lessThanOrEqual - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintLessThanOrEqual() - { - $constraint = PHPUnit_Framework_Assert::lessThanOrEqual(1); - - $this->assertTrue($constraint->evaluate(1, '', TRUE)); - $this->assertFalse($constraint->evaluate(2, '', TRUE)); - $this->assertEquals('is equal to 1 or is less than 1', $constraint->toString()); - $this->assertEquals(2, count($constraint)); - - try { - $constraint->evaluate(2); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_Callback - */ - public function testConstraintCallback() - { - $closureReflect = function($parameter) { - return $parameter; - }; - - $closureWithoutParameter = function() { - return TRUE; - }; - - $constraint = PHPUnit_Framework_Assert::callback($closureWithoutParameter); - $this->assertTrue($constraint->evaluate('', '', TRUE)); - - $constraint = PHPUnit_Framework_Assert::callback($closureReflect); - $this->assertTrue($constraint->evaluate(TRUE, '', TRUE)); - $this->assertFalse($constraint->evaluate(FALSE, '', TRUE)); - - $callback = array($this, 'callbackReturningTrue'); - $constraint = PHPUnit_Framework_Assert::callback($callback); - $this->assertTrue($constraint->evaluate(FALSE, '', TRUE)); - - $callback = array('Framework_ConstraintTest', 'staticCallbackReturningTrue'); - $constraint = PHPUnit_Framework_Assert::callback($callback); - $this->assertTrue($constraint->evaluate(NULL, '', TRUE)); - - $this->assertEquals('is accepted by specified callback', $constraint->toString()); - } - - /** - * @covers PHPUnit_Framework_Constraint_Callback - * @expectedException PHPUnit_Framework_ExpectationFailedException - * @expectedExceptionMessage Failed asserting that 'This fails' is accepted by specified callback. - */ - public function testConstraintCallbackFailure() - { - $constraint = PHPUnit_Framework_Assert::callback(function() { - return FALSE; - }); - $constraint->evaluate('This fails'); - } - - public function callbackReturningTrue() - { - return TRUE; - } - - public static function staticCallbackReturningTrue() - { - return TRUE; - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Assert::lessThanOrEqual - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintLessThanOrEqual2() - { - $constraint = PHPUnit_Framework_Assert::lessThanOrEqual(1); - - try { - $constraint->evaluate(2, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::lessThanOrEqual - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotLessThanOrEqual() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::lessThanOrEqual(1) - ); - - $this->assertTrue($constraint->evaluate(2, '', TRUE)); - $this->assertFalse($constraint->evaluate(1, '', TRUE)); - $this->assertEquals('not( is equal to 1 or is less than 1 )', $constraint->toString()); - $this->assertEquals(2, count($constraint)); - - try { - $constraint->evaluate(1); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEqual - * @covers PHPUnit_Framework_Constraint_LessThan - * @covers PHPUnit_Framework_Constraint_Or - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::lessThanOrEqual - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotLessThanOrEqual2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::lessThanOrEqual(1) - ); - - try { - $constraint->evaluate(1, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasAttribute - * @covers PHPUnit_Framework_Assert::classHasAttribute - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassHasAttribute() - { - $constraint = PHPUnit_Framework_Assert::classHasAttribute('privateAttribute'); - - $this->assertTrue($constraint->evaluate('ClassWithNonPublicAttributes', '', TRUE)); - $this->assertFalse($constraint->evaluate('stdClass', '', TRUE)); - $this->assertEquals('has attribute "privateAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('stdClass'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasAttribute - * @covers PHPUnit_Framework_Assert::classHasAttribute - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassHasAttribute2() - { - $constraint = PHPUnit_Framework_Assert::classHasAttribute('privateAttribute'); - - try { - $constraint->evaluate('stdClass', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::classHasAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassNotHasAttribute() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::classHasAttribute('privateAttribute') - ); - - $this->assertTrue($constraint->evaluate('stdClass', '', TRUE)); - $this->assertFalse($constraint->evaluate('ClassWithNonPublicAttributes', '', TRUE)); - $this->assertEquals('does not have attribute "privateAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::classHasAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassNotHasAttribute2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::classHasAttribute('privateAttribute') - ); - - try { - $constraint->evaluate('ClassWithNonPublicAttributes', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @covers PHPUnit_Framework_Assert::classHasStaticAttribute - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassHasStaticAttribute() - { - $constraint = PHPUnit_Framework_Assert::classHasStaticAttribute('privateStaticAttribute'); - - $this->assertTrue($constraint->evaluate('ClassWithNonPublicAttributes', '', TRUE)); - $this->assertFalse($constraint->evaluate('stdClass', '', TRUE)); - $this->assertEquals('has static attribute "privateStaticAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('stdClass'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @covers PHPUnit_Framework_Assert::classHasStaticAttribute - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassHasStaticAttribute2() - { - $constraint = PHPUnit_Framework_Assert::classHasStaticAttribute('foo'); - - try { - $constraint->evaluate('stdClass', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::classHasStaticAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassNotHasStaticAttribute() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::classHasStaticAttribute('privateStaticAttribute') - ); - - $this->assertTrue($constraint->evaluate('stdClass', '', TRUE)); - $this->assertFalse($constraint->evaluate('ClassWithNonPublicAttributes', '', TRUE)); - $this->assertEquals('does not have static attribute "privateStaticAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('ClassWithNonPublicAttributes'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ClassHasStaticAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::classHasStaticAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintClassNotHasStaticAttribute2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::classHasStaticAttribute('privateStaticAttribute') - ); - - try { - $constraint->evaluate('ClassWithNonPublicAttributes', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ObjectHasAttribute - * @covers PHPUnit_Framework_Assert::objectHasAttribute - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintObjectHasAttribute() - { - $constraint = PHPUnit_Framework_Assert::objectHasAttribute('privateAttribute'); - - $this->assertTrue($constraint->evaluate(new ClassWithNonPublicAttributes, '', TRUE)); - $this->assertFalse($constraint->evaluate(new stdClass, '', TRUE)); - $this->assertEquals('has attribute "privateAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(new stdClass); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ObjectHasAttribute - * @covers PHPUnit_Framework_Assert::objectHasAttribute - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintObjectHasAttribute2() - { - $constraint = PHPUnit_Framework_Assert::objectHasAttribute('privateAttribute'); - - try { - $constraint->evaluate(new stdClass, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ObjectHasAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::objectHasAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintObjectNotHasAttribute() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::objectHasAttribute('privateAttribute') - ); - - $this->assertTrue($constraint->evaluate(new stdClass, '', TRUE)); - $this->assertFalse($constraint->evaluate(new ClassWithNonPublicAttributes, '', TRUE)); - $this->assertEquals('does not have attribute "privateAttribute"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(new ClassWithNonPublicAttributes); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_ObjectHasAttribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::objectHasAttribute - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintObjectNotHasAttribute2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::objectHasAttribute('privateAttribute') - ); - - try { - $constraint->evaluate(new ClassWithNonPublicAttributes, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_PCREMatch - * @covers PHPUnit_Framework_Assert::matchesRegularExpression - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintPCREMatch() - { - $constraint = PHPUnit_Framework_Assert::matchesRegularExpression('/foo/'); - - $this->assertFalse($constraint->evaluate('barbazbar', '', TRUE)); - $this->assertTrue($constraint->evaluate('barfoobar', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/foo/"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('barbazbar'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_PCREMatch - * @covers PHPUnit_Framework_Assert::matchesRegularExpression - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintPCREMatch2() - { - $constraint = PHPUnit_Framework_Assert::matchesRegularExpression('/foo/'); - - try { - $constraint->evaluate('barbazbar', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_PCREMatch - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::matchesRegularExpression - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintPCRENotMatch() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::matchesRegularExpression('/foo/') - ); - - $this->assertTrue($constraint->evaluate('barbazbar', '', TRUE)); - $this->assertFalse($constraint->evaluate('barfoobar', '', TRUE)); - $this->assertEquals('does not match PCRE pattern "/foo/"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('barfoobar'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_PCREMatch - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::matchesRegularExpression - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintPCRENotMatch2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::matchesRegularExpression('/foo/') - ); - - try { - $constraint->evaluate('barfoobar', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals(<<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches() - { - $constraint = PHPUnit_Framework_Assert::matches('*%c*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('***', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*.\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches2() - { - $constraint = PHPUnit_Framework_Assert::matches('*%s*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('***', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*[^\r\n]+\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches3() - { - $constraint = PHPUnit_Framework_Assert::matches('*%i*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('*0*', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*[+-]?\d+\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches4() - { - $constraint = PHPUnit_Framework_Assert::matches('*%d*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('*0*', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*\d+\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches5() - { - $constraint = PHPUnit_Framework_Assert::matches('*%x*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('*0f0f0f*', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*[0-9a-fA-F]+\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringMatches - * @covers PHPUnit_Framework_Assert::matches - * @covers PHPUnit_Framework_Constraint::count - */ - public function testConstraintStringMatches6() - { - $constraint = PHPUnit_Framework_Assert::matches('*%f*'); - $this->assertFalse($constraint->evaluate('**', '', TRUE)); - $this->assertTrue($constraint->evaluate('*1.0*', '', TRUE)); - $this->assertEquals('matches PCRE pattern "/^\*[+-]?\.?\d+\.?\d*(?:[Ee][+-]?\d+)?\*$/s"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringStartsWith - * @covers PHPUnit_Framework_Assert::stringStartsWith - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringStartsWith() - { - $constraint = PHPUnit_Framework_Assert::stringStartsWith('prefix'); - - $this->assertFalse($constraint->evaluate('foo', '', TRUE)); - $this->assertTrue($constraint->evaluate('prefixfoo', '', TRUE)); - $this->assertEquals('starts with "prefix"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('foo'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringStartsWith - * @covers PHPUnit_Framework_Assert::stringStartsWith - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringStartsWith2() - { - $constraint = PHPUnit_Framework_Assert::stringStartsWith('prefix'); - - try { - $constraint->evaluate('foo', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringStartsWith - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::stringStartsWith - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringStartsNotWith() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringStartsWith('prefix') - ); - - $this->assertTrue($constraint->evaluate('foo', '', TRUE)); - $this->assertFalse($constraint->evaluate('prefixfoo', '', TRUE)); - $this->assertEquals('starts not with "prefix"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('prefixfoo'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringStartsWith - * @covers PHPUnit_Framework_Assert::stringStartsWith - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringStartsNotWith2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringStartsWith('prefix') - ); - - try { - $constraint->evaluate('prefixfoo', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringContains - * @covers PHPUnit_Framework_Assert::stringContains - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringContains() - { - $constraint = PHPUnit_Framework_Assert::stringContains('foo'); - - $this->assertFalse($constraint->evaluate('barbazbar', '', TRUE)); - $this->assertTrue($constraint->evaluate('barfoobar', '', TRUE)); - $this->assertEquals('contains "foo"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('barbazbar'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringContains - * @covers PHPUnit_Framework_Assert::stringContains - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringContains2() - { - $constraint = PHPUnit_Framework_Assert::stringContains('foo'); - - try { - $constraint->evaluate('barbazbar', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringContains - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::stringContains - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringNotContains() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringContains('foo') - ); - - $this->assertTrue($constraint->evaluate('barbazbar', '', TRUE)); - $this->assertFalse($constraint->evaluate('barfoobar', '', TRUE)); - $this->assertEquals('does not contain "foo"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('barfoobar'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringContains - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::stringContains - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringNotContains2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringContains('foo') - ); - - try { - $constraint->evaluate('barfoobar', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringEndsWith - * @covers PHPUnit_Framework_Assert::stringEndsWith - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringEndsWith() - { - $constraint = PHPUnit_Framework_Assert::stringEndsWith('suffix'); - - $this->assertFalse($constraint->evaluate('foo', '', TRUE)); - $this->assertTrue($constraint->evaluate('foosuffix', '', TRUE)); - $this->assertEquals('ends with "suffix"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('foo'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringEndsWith - * @covers PHPUnit_Framework_Assert::stringEndsWith - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringEndsWith2() - { - $constraint = PHPUnit_Framework_Assert::stringEndsWith('suffix'); - - try { - $constraint->evaluate('foo', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringEndsWith - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::stringEndsWith - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringEndsNotWith() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringEndsWith('suffix') - ); - - $this->assertTrue($constraint->evaluate('foo', '', TRUE)); - $this->assertFalse($constraint->evaluate('foosuffix', '', TRUE)); - $this->assertEquals('ends not with "suffix"', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate('foosuffix'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_StringEndsWith - * @covers PHPUnit_Framework_Assert::stringEndsWith - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintStringEndsNotWith2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::stringEndsWith('suffix') - ); - - try { - $constraint->evaluate('foosuffix', 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayContains() - { - $constraint = new PHPUnit_Framework_Constraint_TraversableContains('foo'); - - $this->assertFalse($constraint->evaluate(array('bar'), '', TRUE)); - $this->assertTrue($constraint->evaluate(array('foo'), '', TRUE)); - $this->assertEquals("contains 'foo'", $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(array('bar')); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayContains2() - { - $constraint = new PHPUnit_Framework_Constraint_TraversableContains('foo'); - - try { - $constraint->evaluate(array('bar'), 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - */ - public function testConstraintArrayContainsCheckForObjectIdentity() - { - // Check for primitive type. - $constraint = new PHPUnit_Framework_Constraint_TraversableContains('foo', TRUE, TRUE); - - $this->assertFalse($constraint->evaluate(array(0), '', TRUE)); - $this->assertFalse($constraint->evaluate(array(TRUE), '', TRUE)); - - // Default case. - $constraint = new PHPUnit_Framework_Constraint_TraversableContains('foo'); - - $this->assertTrue($constraint->evaluate(array(0), '', TRUE)); - $this->assertTrue($constraint->evaluate(array(TRUE), '', TRUE)); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayNotContains() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - new PHPUnit_Framework_Constraint_TraversableContains('foo') - ); - - $this->assertTrue($constraint->evaluate(array('bar'), '', TRUE)); - $this->assertFalse($constraint->evaluate(array('foo'), '', TRUE)); - $this->assertEquals("does not contain 'foo'", $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(array('foo')); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintArrayNotContains2() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - new PHPUnit_Framework_Constraint_TraversableContains('foo') - ); - - try { - $constraint->evaluate(array('foo'), 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintSplObjectStorageContains() - { - $object = new StdClass; - $constraint = new PHPUnit_Framework_Constraint_TraversableContains($object); - $this->assertStringMatchesFormat("contains stdClass Object &%s ()", $constraint->toString()); - - $storage = new SplObjectStorage; - $this->assertFalse($constraint->evaluate($storage, '', TRUE)); - - $storage->attach($object); - $this->assertTrue($constraint->evaluate($storage, '', TRUE)); - - try { - $constraint->evaluate(new SplObjectStorage); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertStringMatchesFormat( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_TraversableContains - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintSplObjectStorageContains2() - { - $object = new StdClass; - $constraint = new PHPUnit_Framework_Constraint_TraversableContains($object); - - try { - $constraint->evaluate(new SplObjectStorage, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertStringMatchesFormat( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::attributeEqualTo - * @covers PHPUnit_Framework_Constraint_Attribute - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testAttributeEqualTo() - { - $object = new ClassWithNonPublicAttributes; - $constraint = PHPUnit_Framework_Assert::attributeEqualTo('foo', 1); - - $this->assertTrue($constraint->evaluate($object, '', TRUE)); - $this->assertEquals('attribute "foo" is equal to 1', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - $constraint = PHPUnit_Framework_Assert::attributeEqualTo('foo', 2); - - $this->assertFalse($constraint->evaluate($object, '', TRUE)); - - try { - $constraint->evaluate($object); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::attributeEqualTo - * @covers PHPUnit_Framework_Constraint_Attribute - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testAttributeEqualTo2() - { - $object = new ClassWithNonPublicAttributes; - $constraint = PHPUnit_Framework_Assert::attributeEqualTo('foo', 2); - - try { - $constraint->evaluate($object, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::attributeEqualTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Constraint_Attribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testAttributeNotEqualTo() - { - $object = new ClassWithNonPublicAttributes; - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::attributeEqualTo('foo', 2) - ); - - $this->assertTrue($constraint->evaluate($object, '', TRUE)); - $this->assertEquals('attribute "foo" is not equal to 2', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::attributeEqualTo('foo', 1) - ); - - $this->assertFalse($constraint->evaluate($object, '', TRUE)); - - try { - $constraint->evaluate($object); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Assert::attributeEqualTo - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_Constraint_Attribute - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testAttributeNotEqualTo2() - { - $object = new ClassWithNonPublicAttributes; - $constraint = PHPUnit_Framework_Assert::logicalNot( - PHPUnit_Framework_Assert::attributeEqualTo('foo', 1) - ); - - try { - $constraint->evaluate($object, 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEmpty - * @covers PHPUnit_Framework_Constraint::count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsEmpty() - { - $constraint = new PHPUnit_Framework_Constraint_IsEmpty; - - $this->assertFalse($constraint->evaluate(array('foo'), '', TRUE)); - $this->assertTrue($constraint->evaluate(array(), '', TRUE)); - $this->assertEquals('is empty', $constraint->toString()); - $this->assertEquals(1, count($constraint)); - - try { - $constraint->evaluate(array('foo')); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_IsEmpty - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintIsEmpty2() - { - $constraint = new PHPUnit_Framework_Constraint_IsEmpty; - - try { - $constraint->evaluate(array('foo'), 'custom message'); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_Count - */ - public function testConstraintCountWithAnArray() - { - $constraint = new PHPUnit_Framework_Constraint_Count(5); - - $this->assertTrue($constraint->evaluate(array(1,2,3,4,5), '', TRUE)); - $this->assertFalse($constraint->evaluate(array(1,2,3,4), '', TRUE)); - } - - /** - * @covers PHPUnit_Framework_Constraint_Count - */ - public function testConstraintCountWithAnIteratorWhichDoesNotImplementCountable() - { - $constraint = new PHPUnit_Framework_Constraint_Count(5); - - $this->assertTrue($constraint->evaluate(new TestIterator(array(1,2,3,4,5)), '', TRUE)); - $this->assertFalse($constraint->evaluate(new TestIterator(array(1,2,3,4)), '', TRUE)); - } - - /** - * @covers PHPUnit_Framework_Constraint_Count - */ - public function testConstraintCountWithAnObjectImplementingCountable() - { - $constraint = new PHPUnit_Framework_Constraint_Count(5); - - $this->assertTrue($constraint->evaluate(new ArrayObject(array(1,2,3,4,5)), '', TRUE)); - $this->assertFalse($constraint->evaluate(new ArrayObject(array(1,2,3,4)), '', TRUE)); - } - - /** - * @covers PHPUnit_Framework_Constraint_Count - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintCountFailing() - { - $constraint = new PHPUnit_Framework_Constraint_Count(5); - - try { - $constraint->evaluate(array(1,2)); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_Count - * @covers PHPUnit_Framework_Constraint_Not - * @covers PHPUnit_Framework_Assert::logicalNot - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintNotCountFailing() - { - $constraint = PHPUnit_Framework_Assert::logicalNot( - new PHPUnit_Framework_Constraint_Count(2) - ); - - try { - $constraint->evaluate(array(1,2)); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } - - /** - * @covers PHPUnit_Framework_Constraint_Exception - * @covers PHPUnit_Framework_TestFailure::exceptionToString - */ - public function testConstraintException() - { - $constraint = new PHPUnit_Framework_Constraint_Exception('FoobarException'); - $exception = new DummyException('Test'); - $stackTrace = $exception->getTraceAsString(); - - try { - $constraint->evaluate($exception); - } - - catch (PHPUnit_Framework_ExpectationFailedException $e) { - $this->assertEquals( - <<fail(); - } -} diff --git a/Tests/Framework/SuiteTest.php b/Tests/Framework/SuiteTest.php deleted file mode 100644 index 5b61f7338f8..00000000000 --- a/Tests/Framework/SuiteTest.php +++ /dev/null @@ -1,185 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'InheritedTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NoTestCaseClass.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NoTestCases.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NotPublicTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NotVoidTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'OneTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'OverrideTestCase.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Framework_SuiteTest extends PHPUnit_Framework_TestCase { - protected $result; - - protected function setUp() - { - $this->result = new PHPUnit_Framework_TestResult; - } - - public static function suite() - { - $suite = new PHPUnit_Framework_TestSuite; - - $suite->addTest(new Framework_SuiteTest('testAddTestSuite')); - $suite->addTest(new Framework_SuiteTest('testInheritedTests')); - $suite->addTest(new Framework_SuiteTest('testNoTestCases')); - $suite->addTest(new Framework_SuiteTest('testNoTestCaseClass')); - $suite->addTest(new Framework_SuiteTest('testNotExistingTestCase')); - $suite->addTest(new Framework_SuiteTest('testNotPublicTestCase')); - $suite->addTest(new Framework_SuiteTest('testNotVoidTestCase')); - $suite->addTest(new Framework_SuiteTest('testOneTestCase')); - $suite->addTest(new Framework_SuiteTest('testShadowedTests')); - - return $suite; - } - - public function testAddTestSuite() - { - $suite = new PHPUnit_Framework_TestSuite( - 'OneTestCase' - ); - - $suite->run($this->result); - - $this->assertEquals(1, count($this->result)); - } - - public function testInheritedTests() - { - $suite = new PHPUnit_Framework_TestSuite( - 'InheritedTestCase' - ); - - $suite->run($this->result); - - $this->assertTrue($this->result->wasSuccessful()); - $this->assertEquals(2, count($this->result)); - } - - public function testNoTestCases() - { - $suite = new PHPUnit_Framework_TestSuite( - 'NoTestCases' - ); - - $suite->run($this->result); - - $this->assertTrue(!$this->result->wasSuccessful()); - $this->assertEquals(1, $this->result->failureCount()); - $this->assertEquals(1, count($this->result)); - } - - /** - * @expectedException PHPUnit_Framework_Exception - */ - public function testNoTestCaseClass() - { - $suite = new PHPUnit_Framework_TestSuite('NoTestCaseClass'); - } - - public function testNotExistingTestCase() - { - $suite = new Framework_SuiteTest('notExistingMethod'); - - $suite->run($this->result); - - $this->assertEquals(0, $this->result->errorCount()); - $this->assertEquals(1, $this->result->failureCount()); - $this->assertEquals(1, count($this->result)); - } - - public function testNotPublicTestCase() - { - $suite = new PHPUnit_Framework_TestSuite( - 'NotPublicTestCase' - ); - - $this->assertEquals(2, count($suite)); - } - - public function testNotVoidTestCase() - { - $suite = new PHPUnit_Framework_TestSuite( - 'NotVoidTestCase' - ); - - $this->assertEquals(1, count($suite)); - } - - public function testOneTestCase() - { - $suite = new PHPUnit_Framework_TestSuite( - 'OneTestCase' - ); - - $suite->run($this->result); - - $this->assertEquals(0, $this->result->errorCount()); - $this->assertEquals(0, $this->result->failureCount()); - $this->assertEquals(1, count($this->result)); - $this->assertTrue($this->result->wasSuccessful()); - } - - public function testShadowedTests() - { - $suite = new PHPUnit_Framework_TestSuite( - 'OverrideTestCase' - ); - - $suite->run($this->result); - - $this->assertEquals(1, count($this->result)); - } -} diff --git a/Tests/Framework/TestCaseTest.php b/Tests/Framework/TestCaseTest.php deleted file mode 100644 index f762c7f217c..00000000000 --- a/Tests/Framework/TestCaseTest.php +++ /dev/null @@ -1,459 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Error.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInAssertPostConditionsTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInAssertPreConditionsTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInSetUpTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInTearDownTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionInTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Failure.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NoArgTestCaseTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'OutputTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'RequirementsTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Singleton.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ThrowExceptionTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ThrowNoExceptionTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'WasRun.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ChangeCurrentWorkingDirectoryTest.php'; - -$GLOBALS['a'] = 'a'; -$_ENV['b'] = 'b'; -$_POST['c'] = 'c'; -$_GET['d'] = 'd'; -$_COOKIE['e'] = 'e'; -$_SERVER['f'] = 'f'; -$_FILES['g'] = 'g'; -$_REQUEST['h'] = 'h'; -$GLOBALS['i'] = 'i'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Framework_TestCaseTest extends PHPUnit_Framework_TestCase -{ - protected $backupGlobalsBlacklist = array('i', 'singleton'); - - public function testCaseToString() - { - $this->assertEquals( - 'Framework_TestCaseTest::testCaseToString', - $this->toString() - ); - } - - public function testSuccess() - { - $test = new Success; - $result = $test->run(); - - $this->assertEquals(0, $result->errorCount()); - $this->assertEquals(0, $result->failureCount()); - $this->assertEquals(1, count($result)); - } - - public function testFailure() - { - $test = new Failure; - $result = $test->run(); - - $this->assertEquals(0, $result->errorCount()); - $this->assertEquals(1, $result->failureCount()); - $this->assertEquals(1, count($result)); - } - - public function testError() - { - $test = new Error; - $result = $test->run(); - - $this->assertEquals(1, $result->errorCount()); - $this->assertEquals(0, $result->failureCount()); - $this->assertEquals(1, count($result)); - } - - public function testExceptionInSetUp() - { - $test = new ExceptionInSetUpTest('testSomething'); - $result = $test->run(); - - $this->assertTrue($test->setUp); - $this->assertFalse($test->assertPreConditions); - $this->assertFalse($test->testSomething); - $this->assertFalse($test->assertPostConditions); - $this->assertTrue($test->tearDown); - } - - public function testExceptionInAssertPreConditions() - { - $test = new ExceptionInAssertPreConditionsTest('testSomething'); - $result = $test->run(); - - $this->assertTrue($test->setUp); - $this->assertTrue($test->assertPreConditions); - $this->assertFalse($test->testSomething); - $this->assertFalse($test->assertPostConditions); - $this->assertTrue($test->tearDown); - } - - public function testExceptionInTest() - { - $test = new ExceptionInTest('testSomething'); - $result = $test->run(); - - $this->assertTrue($test->setUp); - $this->assertTrue($test->assertPreConditions); - $this->assertTrue($test->testSomething); - $this->assertFalse($test->assertPostConditions); - $this->assertTrue($test->tearDown); - } - - public function testExceptionInAssertPostConditions() - { - $test = new ExceptionInAssertPostConditionsTest('testSomething'); - $result = $test->run(); - - $this->assertTrue($test->setUp); - $this->assertTrue($test->assertPreConditions); - $this->assertTrue($test->testSomething); - $this->assertTrue($test->assertPostConditions); - $this->assertTrue($test->tearDown); - } - - public function testExceptionInTearDown() - { - $test = new ExceptionInTearDownTest('testSomething'); - $result = $test->run(); - - $this->assertTrue($test->setUp); - $this->assertTrue($test->assertPreConditions); - $this->assertTrue($test->testSomething); - $this->assertTrue($test->assertPostConditions); - $this->assertTrue($test->tearDown); - } - - public function testNoArgTestCasePasses() - { - $result = new PHPUnit_Framework_TestResult; - $t = new PHPUnit_Framework_TestSuite('NoArgTestCaseTest'); - - $t->run($result); - - $this->assertEquals(1, count($result)); - $this->assertEquals(0, $result->failureCount()); - $this->assertEquals(0, $result->errorCount()); - } - - public function testWasRun() - { - $test = new WasRun; - $test->run(); - - $this->assertTrue($test->wasRun); - } - - public function testException() - { - $test = new ThrowExceptionTestCase('test'); - $test->setExpectedException('RuntimeException'); - - $result = $test->run(); - - $this->assertEquals(1, count($result)); - $this->assertTrue($result->wasSuccessful()); - } - - public function testNoException() - { - $test = new ThrowNoExceptionTestCase('test'); - $test->setExpectedException('RuntimeException'); - - $result = $test->run(); - - $this->assertEquals(1, $result->failureCount()); - $this->assertEquals(1, count($result)); - } - - public function testWrongException() - { - $test = new ThrowExceptionTestCase('test'); - $test->setExpectedException('InvalidArgumentException'); - - $result = $test->run(); - - $this->assertEquals(1, $result->failureCount()); - $this->assertEquals(1, count($result)); - } - - /** - * @backupGlobals enabled - */ - public function testGlobalsBackupPre() - { - global $a; - global $i; - - $this->assertEquals('a', $a); - $this->assertEquals('a', $GLOBALS['a']); - $this->assertEquals('b', $_ENV['b']); - $this->assertEquals('c', $_POST['c']); - $this->assertEquals('d', $_GET['d']); - $this->assertEquals('e', $_COOKIE['e']); - $this->assertEquals('f', $_SERVER['f']); - $this->assertEquals('g', $_FILES['g']); - $this->assertEquals('h', $_REQUEST['h']); - $this->assertEquals('i', $i); - $this->assertEquals('i', $GLOBALS['i']); - - $GLOBALS['a'] = 'aa'; - $GLOBALS['foo'] = 'bar'; - $_ENV['b'] = 'bb'; - $_POST['c'] = 'cc'; - $_GET['d'] = 'dd'; - $_COOKIE['e'] = 'ee'; - $_SERVER['f'] = 'ff'; - $_FILES['g'] = 'gg'; - $_REQUEST['h'] = 'hh'; - $GLOBALS['i'] = 'ii'; - - $this->assertEquals('aa', $a); - $this->assertEquals('aa', $GLOBALS['a']); - $this->assertEquals('bar', $GLOBALS['foo']); - $this->assertEquals('bb', $_ENV['b']); - $this->assertEquals('cc', $_POST['c']); - $this->assertEquals('dd', $_GET['d']); - $this->assertEquals('ee', $_COOKIE['e']); - $this->assertEquals('ff', $_SERVER['f']); - $this->assertEquals('gg', $_FILES['g']); - $this->assertEquals('hh', $_REQUEST['h']); - $this->assertEquals('ii', $i); - $this->assertEquals('ii', $GLOBALS['i']); - } - - public function testGlobalsBackupPost() - { - global $a; - global $i; - - $this->assertEquals('a', $a); - $this->assertEquals('a', $GLOBALS['a']); - $this->assertEquals('b', $_ENV['b']); - $this->assertEquals('c', $_POST['c']); - $this->assertEquals('d', $_GET['d']); - $this->assertEquals('e', $_COOKIE['e']); - $this->assertEquals('f', $_SERVER['f']); - $this->assertEquals('g', $_FILES['g']); - $this->assertEquals('h', $_REQUEST['h']); - $this->assertEquals('ii', $i); - $this->assertEquals('ii', $GLOBALS['i']); - - $this->assertArrayNotHasKey('foo', $GLOBALS); - } - - /** - * @backupGlobals enabled - * @backupStaticAttributes enabled - */ - public function testStaticAttributesBackupPre() - { - $GLOBALS['singleton'] = Singleton::getInstance(); - } - - public function testStaticAttributesBackupPost() - { - $this->assertNotSame($GLOBALS['singleton'], Singleton::getInstance()); - } - - public function testExpectOutputStringFooActualFoo() - { - $test = new OutputTestCase('testExpectOutputStringFooActualFoo'); - $result = $test->run(); - - $this->assertEquals(1, count($result)); - $this->assertTrue($result->wasSuccessful()); - } - - public function testExpectOutputStringFooActualBar() - { - $test = new OutputTestCase('testExpectOutputStringFooActualBar'); - $result = $test->run(); - - $this->assertEquals(1, count($result)); - $this->assertFalse($result->wasSuccessful()); - } - - public function testExpectOutputRegexFooActualFoo() - { - $test = new OutputTestCase('testExpectOutputRegexFooActualFoo'); - $result = $test->run(); - - $this->assertEquals(1, count($result)); - $this->assertTrue($result->wasSuccessful()); - } - - public function testExpectOutputRegexFooActualBar() - { - $test = new OutputTestCase('testExpectOutputRegexFooActualBar'); - $result = $test->run(); - - $this->assertEquals(1, count($result)); - $this->assertFalse($result->wasSuccessful()); - } - - public function testSkipsIfRequiresHigherVersionOfPHPUnit() - { - $test = new RequirementsTest('testAlwaysSkip'); - $result = $test->run(); - - $this->assertEquals(1, $result->skippedCount()); - $this->assertEquals( - 'PHPUnit 1111111 (or later) is required.', - $test->getStatusMessage() - ); - } - - public function testSkipsIfRequiresHigherVersionOfPHP() - { - $test = new RequirementsTest('testAlwaysSkip2'); - $result = $test->run(); - - $this->assertEquals(1, $result->skippedCount()); - $this->assertEquals( - 'PHP 9999999 (or later) is required.', - $test->getStatusMessage() - ); - } - - public function testSkipsIfRequiresNonExistingOs() - { - $test = new RequirementsTest('testAlwaysSkip3'); - $result = $test->run(); - - $this->assertEquals(1, $result->skippedCount()); - $this->assertEquals( - 'Operating system matching /DOESNOTEXIST/i is required.', - $test->getStatusMessage() - ); - } - - public function testSkipsIfRequiresNonExistingFunction() - { - $test = new RequirementsTest('testNine'); - $result = $test->run(); - - $this->assertEquals(1, $result->skippedCount()); - $this->assertEquals( - 'Function testFunc is required.', - $test->getStatusMessage() - ); - } - - public function testSkipsIfRequiresNonExistingExtension() - { - $test = new RequirementsTest('testTen'); - $result = $test->run(); - - $this->assertEquals( - 'Extension testExt is required.', - $test->getStatusMessage() - ); - } - - public function testSkipsProvidesMessagesForAllSkippingReasons() - { - $test = new RequirementsTest('testAllPossibleRequirements'); - $result = $test->run(); - - $this->assertEquals( - 'PHP 99-dev (or later) is required.' . PHP_EOL . - 'PHPUnit 9-dev (or later) is required.' . PHP_EOL . - 'Operating system matching /DOESNOTEXIST/i is required.' . PHP_EOL . - 'Function testFuncOne is required.' . PHP_EOL . - 'Function testFuncTwo is required.' . PHP_EOL . - 'Extension testExtOne is required.' . PHP_EOL . - 'Extension testExtTwo is required.', - $test->getStatusMessage() - ); - } - - public function testRequiringAnExistingFunctionDoesNotSkip() - { - $test = new RequirementsTest('testExistingFunction'); - $result = $test->run(); - $this->assertEquals(0, $result->skippedCount()); - } - - public function testRequiringAnExistingExtensionDoesNotSkip() - { - $test = new RequirementsTest('testExistingExtension'); - $result = $test->run(); - $this->assertEquals(0, $result->skippedCount()); - } - - public function testRequiringAnExistingOsDoesNotSkip() - { - $test = new RequirementsTest('testExistingOs'); - $result = $test->run(); - $this->assertEquals(0, $result->skippedCount()); - } - - public function testCurrentWorkingDirectoryIsRestored() - { - $expectedCwd = getcwd(); - - $test = new ChangeCurrentWorkingDirectoryTest('testSomethingThatChangesTheCwd'); - $test->run(); - - $this->assertSame($expectedCwd, getcwd()); - } - -} diff --git a/Tests/Framework/TestImplementorTest.php b/Tests/Framework/TestImplementorTest.php deleted file mode 100644 index 4f8d9e1f5a8..00000000000 --- a/Tests/Framework/TestImplementorTest.php +++ /dev/null @@ -1,79 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'DoubleTestCase.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Framework_TestImplementorTest extends PHPUnit_Framework_TestCase -{ - protected $test; - - public function __construct() - { - $this->test = new DoubleTestCase( - new Success - ); - } - - public function testSuccessfulRun() - { - $result = new PHPUnit_Framework_TestResult; - - $this->test->run($result); - - $this->assertEquals(count($this->test), count($result)); - $this->assertEquals(0, $result->errorCount()); - $this->assertEquals(0, $result->failureCount()); - } -} diff --git a/Tests/Framework/TestListenerTest.php b/Tests/Framework/TestListenerTest.php deleted file mode 100644 index c242aff3e2b..00000000000 --- a/Tests/Framework/TestListenerTest.php +++ /dev/null @@ -1,145 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Error.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Failure.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'Success.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Framework_TestListenerTest extends PHPUnit_Framework_TestCase implements PHPUnit_Framework_TestListener -{ - protected $endCount; - protected $errorCount; - protected $failureCount; - protected $notImplementedCount; - protected $skippedCount; - protected $result; - protected $startCount; - - public function addError(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->errorCount++; - } - - public function addFailure(PHPUnit_Framework_Test $test, PHPUnit_Framework_AssertionFailedError $e, $time) - { - $this->failureCount++; - } - - public function addIncompleteTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->notImplementedCount++; - } - - public function addSkippedTest(PHPUnit_Framework_Test $test, Exception $e, $time) - { - $this->skippedCount++; - } - - public function startTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - public function endTestSuite(PHPUnit_Framework_TestSuite $suite) - { - } - - public function startTest(PHPUnit_Framework_Test $test) - { - $this->startCount++; - } - - public function endTest(PHPUnit_Framework_Test $test, $time) - { - $this->endCount++; - } - - protected function setUp() - { - $this->result = new PHPUnit_Framework_TestResult; - $this->result->addListener($this); - - $this->endCount = 0; - $this->failureCount = 0; - $this->notImplementedCount = 0; - $this->skippedCount = 0; - $this->startCount = 0; - } - - public function testError() - { - $test = new Error; - $test->run($this->result); - - $this->assertEquals(1, $this->errorCount); - $this->assertEquals(1, $this->endCount); - } - - public function testFailure() - { - $test = new Failure; - $test->run($this->result); - - $this->assertEquals(1, $this->failureCount); - $this->assertEquals(1, $this->endCount); - } - - public function testStartStop() - { - $test = new Success; - $test->run($this->result); - - $this->assertEquals(1, $this->startCount); - $this->assertEquals(1, $this->endCount); - } -} diff --git a/Tests/Regression/1021.phpt b/Tests/Regression/1021.phpt deleted file mode 100644 index 389e8cf2fe6..00000000000 --- a/Tests/Regression/1021.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -#1021: Depending on a test that uses a data provider does not work ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 1 assertion) diff --git a/Tests/Regression/1021/Issue1021Test.php b/Tests/Regression/1021/Issue1021Test.php deleted file mode 100644 index 422d580c82e..00000000000 --- a/Tests/Regression/1021/Issue1021Test.php +++ /dev/null @@ -1,23 +0,0 @@ -assertTrue($data); - } - - /** - * @depends testSomething - */ - public function testSomethingElse() - { - } - - public function provider() - { - return array(array(TRUE)); - } -} diff --git a/Tests/Regression/523.phpt b/Tests/Regression/523.phpt deleted file mode 100644 index 2016dbc5f1b..00000000000 --- a/Tests/Regression/523.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -#523: assertAttributeEquals does not work with classes extending ArrayIterator ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) diff --git a/Tests/Regression/523/Issue523Test.php b/Tests/Regression/523/Issue523Test.php deleted file mode 100644 index 80124f1daa7..00000000000 --- a/Tests/Regression/523/Issue523Test.php +++ /dev/null @@ -1,13 +0,0 @@ -assertAttributeEquals('foo', 'field', new Issue523()); - } -}; - -class Issue523 extends ArrayIterator -{ - protected $field = 'foo'; -} diff --git a/Tests/Regression/578.phpt b/Tests/Regression/578.phpt deleted file mode 100644 index dca8300335a..00000000000 --- a/Tests/Regression/578.phpt +++ /dev/null @@ -1,37 +0,0 @@ ---TEST-- -#578: Double printing of trace line for exceptions from notices and warnings ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -EEE - -Time: %s, Memory: %sMb - -There were 3 errors: - -1) Issue578Test::testNoticesDoublePrintStackTrace -Invalid error type specified - -%s/Issue578Test.php:%i - -2) Issue578Test::testWarningsDoublePrintStackTrace -Invalid error type specified - -%s/Issue578Test.php:%i - -3) Issue578Test::testUnexpectedExceptionsPrintsCorrectly -Exception: Double printed exception - -%s/Issue578Test.php:%i - -FAILURES! -Tests: 3, Assertions: 0, Errors: 3. diff --git a/Tests/Regression/578/Issue578Test.php b/Tests/Regression/578/Issue578Test.php deleted file mode 100644 index 262d97f64d2..00000000000 --- a/Tests/Regression/578/Issue578Test.php +++ /dev/null @@ -1,20 +0,0 @@ -iniSet('error_reporting', E_ALL | E_NOTICE); - trigger_error('Stack Trace Test Notice', E_NOTICE); - } - - public function testWarningsDoublePrintStackTrace() - { - $this->iniSet('error_reporting', E_ALL | E_NOTICE); - trigger_error('Stack Trace Test Notice', E_WARNING); - } - - public function testUnexpectedExceptionsPrintsCorrectly() - { - throw new Exception('Double printed exception'); - } -} diff --git a/Tests/Regression/684.phpt b/Tests/Regression/684.phpt deleted file mode 100644 index 69c58764916..00000000000 --- a/Tests/Regression/684.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -#684: Unable to find test class when no test methods exists ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Warning -No tests found in class "Foo_Bar_Issue684Test". - - -FAILURES! -Tests: 1, Assertions: 0, Failures: 1. diff --git a/Tests/Regression/684/Issue684Test.php b/Tests/Regression/684/Issue684Test.php deleted file mode 100644 index e8e5d87ec72..00000000000 --- a/Tests/Regression/684/Issue684Test.php +++ /dev/null @@ -1,4 +0,0 @@ - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 0 assertions) diff --git a/Tests/Regression/783/ChildSuite.php b/Tests/Regression/783/ChildSuite.php deleted file mode 100644 index 8bac5144b0a..00000000000 --- a/Tests/Regression/783/ChildSuite.php +++ /dev/null @@ -1,15 +0,0 @@ -addTestSuite('OneTest'); - $suite->addTestSuite('TwoTest'); - - return $suite; - } -} diff --git a/Tests/Regression/783/OneTest.php b/Tests/Regression/783/OneTest.php deleted file mode 100644 index 3daa91b644f..00000000000 --- a/Tests/Regression/783/OneTest.php +++ /dev/null @@ -1,10 +0,0 @@ -addTest(ChildSuite::suite()); - - return $suite; - } -} diff --git a/Tests/Regression/783/TwoTest.php b/Tests/Regression/783/TwoTest.php deleted file mode 100644 index 8fa9958c433..00000000000 --- a/Tests/Regression/783/TwoTest.php +++ /dev/null @@ -1,10 +0,0 @@ - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.FFF - -Time: %s, Memory: %sMb - -There were 3 failures: - -1) Issue244Test::testFails -Failed asserting that '123StringCode' is equal to expected exception code 'OtherString'. - -%s:%i - -2) Issue244Test::testFailsTooIfExpectationIsANumber -Failed asserting that '123StringCode' is equal to expected exception code 123. - -%s:%i - -3) Issue244Test::testFailsTooIfExceptionCodeIsANumber -Failed asserting that 123 is equal to expected exception code '123String'. - -%s:%i - -FAILURES! -Tests: 4, Assertions: 8, Failures: 3. diff --git a/Tests/Regression/GitHub/244/Issue244Test.php b/Tests/Regression/GitHub/244/Issue244Test.php deleted file mode 100644 index 621c4cf5420..00000000000 --- a/Tests/Regression/GitHub/244/Issue244Test.php +++ /dev/null @@ -1,55 +0,0 @@ -code = '123StringCode'; - } -} - -class Issue244ExceptionIntCode extends Exception -{ - public function __construct() - { - $this->code = 123; - } -} diff --git a/Tests/Regression/GitHub/322.phpt b/Tests/Regression/GitHub/322.phpt deleted file mode 100644 index 9642e1dce6e..00000000000 --- a/Tests/Regression/GitHub/322.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -GH-322: group commandline option should override group/exclude setting in phpunit.xml ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Configuration read from %s - - -Starting test 'Issue322Test::testOne'. -. - -Time: %s, Memory: %sMb - -OK (1 test, 0 assertions) diff --git a/Tests/Regression/GitHub/322/Issue322Test.php b/Tests/Regression/GitHub/322/Issue322Test.php deleted file mode 100644 index 618bcaa19c9..00000000000 --- a/Tests/Regression/GitHub/322/Issue322Test.php +++ /dev/null @@ -1,17 +0,0 @@ - - - Test.php - - - - - one - - - \ No newline at end of file diff --git a/Tests/Regression/GitHub/433.phpt b/Tests/Regression/GitHub/433.phpt deleted file mode 100644 index 211a1a16038..00000000000 --- a/Tests/Regression/GitHub/433.phpt +++ /dev/null @@ -1,33 +0,0 @@ ---TEST-- -GH-433: expectOutputString not completely working as expected ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -..F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Issue433Test::testNotMatchingOutput -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ --'foo' -+'bar' - - -FAILURES! -Tests: 3, Assertions: 3, Failures: 1. - diff --git a/Tests/Regression/GitHub/433/Issue433Test.php b/Tests/Regression/GitHub/433/Issue433Test.php deleted file mode 100644 index e0a91b35b28..00000000000 --- a/Tests/Regression/GitHub/433/Issue433Test.php +++ /dev/null @@ -1,21 +0,0 @@ -expectOutputString('test'); - print 'test'; - } - - public function testOutputWithExpectationAfter() - { - print 'test'; - $this->expectOutputString('test'); - } - - public function testNotMatchingOutput() - { - print 'bar'; - $this->expectOutputString('foo'); - } -} diff --git a/Tests/Regression/GitHub/445.phpt b/Tests/Regression/GitHub/445.phpt deleted file mode 100644 index a641ade3021..00000000000 --- a/Tests/Regression/GitHub/445.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -GH-455: expectOutputString not working in strict mode ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -..F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Issue445Test::testNotMatchingOutput -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ --'foo' -+'bar' - - -FAILURES! -Tests: 3, Assertions: 3, Failures: 1. - diff --git a/Tests/Regression/GitHub/445/Issue445Test.php b/Tests/Regression/GitHub/445/Issue445Test.php deleted file mode 100644 index c3090259ebc..00000000000 --- a/Tests/Regression/GitHub/445/Issue445Test.php +++ /dev/null @@ -1,21 +0,0 @@ -expectOutputString('test'); - print 'test'; - } - - public function testOutputWithExpectationAfter() - { - print 'test'; - $this->expectOutputString('test'); - } - - public function testNotMatchingOutput() - { - print 'bar'; - $this->expectOutputString('foo'); - } -} diff --git a/Tests/Regression/GitHub/498.phpt b/Tests/Regression/GitHub/498.phpt deleted file mode 100644 index c8b62c3901b..00000000000 --- a/Tests/Regression/GitHub/498.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -GH-498: The test methods won't be run if a dataProvider throws Exception and --group is added in command line ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Warning -The data provider specified for Issue498Test::shouldBeFalse is invalid. -Can't create the data - - -FAILURES! -Tests: 1, Assertions: 0, Failures: 1. - diff --git a/Tests/Regression/GitHub/498/Issue498Test.php b/Tests/Regression/GitHub/498/Issue498Test.php deleted file mode 100644 index a42c62959ee..00000000000 --- a/Tests/Regression/GitHub/498/Issue498Test.php +++ /dev/null @@ -1,46 +0,0 @@ -assertTrue(true); - } - - - /** - * @test - * @dataProvider shouldBeFalseDataProvider - * @group trueOnly - */ - public function shouldBeFalse($testData) - { - $this->assertFalse(false); - } - - public function shouldBeTrueDataProvider() - { - - //throw new Exception("Can't create the data"); - return array( - array(true), - array(false) - ); - } - - public function shouldBeFalseDataProvider() - { - - throw new Exception("Can't create the data"); - return array( - array(true), - array(false) - ); - } -} diff --git a/Tests/Regression/GitHub/503.phpt b/Tests/Regression/GitHub/503.phpt deleted file mode 100644 index 36e2d95bf3d..00000000000 --- a/Tests/Regression/GitHub/503.phpt +++ /dev/null @@ -1,34 +0,0 @@ ---TEST-- -GH-503: assertEquals() Line Ending Differences Are Obscure ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Issue503Test::testCompareDifferentLineEndings -Failed asserting that two strings are identical. ---- Expected -+++ Actual -@@ @@ - #Warning: Strings contain different line endings! - foo - -%s:%i - -FAILURES! -Tests: 1, Assertions: 1, Failures: 1. - diff --git a/Tests/Regression/GitHub/503/Issue503Test.php b/Tests/Regression/GitHub/503/Issue503Test.php deleted file mode 100644 index 75ca8d45471..00000000000 --- a/Tests/Regression/GitHub/503/Issue503Test.php +++ /dev/null @@ -1,11 +0,0 @@ -assertSame( - "foo\n", - "foo\r\n" - ); - } -} diff --git a/Tests/Regression/GitHub/581.phpt b/Tests/Regression/GitHub/581.phpt deleted file mode 100644 index 29b35f275ad..00000000000 --- a/Tests/Regression/GitHub/581.phpt +++ /dev/null @@ -1,43 +0,0 @@ ---TEST-- -GH-581: PHPUnit_Util_Type::export adds extra newlines in Windows ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Issue581Test::testExportingObjectsDoesNotBreakWindowsLineFeeds -Failed asserting that two objects are equal. ---- Expected -+++ Actual -@@ @@ - stdClass Object ( - 0 => 1 - 1 => 2 - 2 => 'Test\n' - 3 => 4 -- 4 => 5 -+ 4 => 1 - 5 => 6 - 6 => 7 - 7 => 8 - ) - -%s:%i - -FAILURES! -Tests: 1, Assertions: 1, Failures: 1. - diff --git a/Tests/Regression/GitHub/581/Issue581Test.php b/Tests/Regression/GitHub/581/Issue581Test.php deleted file mode 100644 index 201780cd68b..00000000000 --- a/Tests/Regression/GitHub/581/Issue581Test.php +++ /dev/null @@ -1,10 +0,0 @@ -assertEquals( - (object)array(1,2,"Test\r\n",4,5,6,7,8), - (object)array(1,2,"Test\r\n",4,1,6,7,8) - ); - } -} diff --git a/Tests/Regression/GitHub/74.phpt b/Tests/Regression/GitHub/74.phpt deleted file mode 100644 index b4d6aecfb2a..00000000000 --- a/Tests/Regression/GitHub/74.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -GH-74: catchable fatal error in 3.5 ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -E - -Time: %s, Memory: %sMb - -There was 1 error: - -1) Issue74Test::testCreateAndThrowNewExceptionInProcessIsolation -NewException: Testing GH-74 - -%s/Tests/Regression/GitHub/74/Issue74Test.php:7 -%s - -FAILURES! -Tests: 1, Assertions: 0, Errors: 1. diff --git a/Tests/Regression/GitHub/74/Issue74Test.php b/Tests/Regression/GitHub/74/Issue74Test.php deleted file mode 100644 index 4d68c5519ec..00000000000 --- a/Tests/Regression/GitHub/74/Issue74Test.php +++ /dev/null @@ -1,9 +0,0 @@ - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Warning -The data provider specified for Issue765Test::testDependent is invalid. - - -FAILURES! -Tests: 2, Assertions: 1, Failures: 1. - diff --git a/Tests/Regression/GitHub/765/Issue765Test.php b/Tests/Regression/GitHub/765/Issue765Test.php deleted file mode 100644 index a47474b27bf..00000000000 --- a/Tests/Regression/GitHub/765/Issue765Test.php +++ /dev/null @@ -1,22 +0,0 @@ -assertTrue(true); - } - - /** - * @depends testDependee - * @dataProvider dependentProvider - */ - public function testDependent($a) - { - $this->assertTrue(true); - } - - public function dependentProvider() - { - throw new Exception; - } -} diff --git a/Tests/Regression/GitHub/863.phpt b/Tests/Regression/GitHub/863.phpt deleted file mode 100644 index 56f35fc5823..00000000000 --- a/Tests/Regression/GitHub/863.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -GH-863: Number of tests to run calculated incorrectly when --repeat is used ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -............................................................... 63 / 150 ( 42%) -............................................................... 126 / 150 ( 84%) -........................ - -Time: %i %s, Memory: %sMb - -OK (150 tests, 150 assertions) - diff --git a/Tests/Runner/BaseTestRunnerTest.php b/Tests/Runner/BaseTestRunnerTest.php deleted file mode 100644 index 5d84d0e03b4..00000000000 --- a/Tests/Runner/BaseTestRunnerTest.php +++ /dev/null @@ -1,65 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.0.0 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'MockRunner.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'NonStatic.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.0.0 - */ -class Runner_BaseTestRunnerTest extends PHPUnit_Framework_TestCase -{ - public function testInvokeNonStaticSuite() - { - $runner = new MockRunner; - $runner->getTest('NonStatic'); - } -} diff --git a/Tests/TextUI/abstract-test-class.phpt b/Tests/TextUI/abstract-test-class.phpt deleted file mode 100644 index 16829fdd6b4..00000000000 --- a/Tests/TextUI/abstract-test-class.phpt +++ /dev/null @@ -1,30 +0,0 @@ ---TEST-- -phpunit AbstractTest ../_files/AbstractTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Warning -Cannot instantiate class "AbstractTest". - -%s:%i - -FAILURES! -Tests: 1, Assertions: 0, Failures: 1. - diff --git a/Tests/TextUI/concrete-test-class.phpt b/Tests/TextUI/concrete-test-class.phpt deleted file mode 100644 index 1fd8c06ff11..00000000000 --- a/Tests/TextUI/concrete-test-class.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit ConcreteTest ../_files/ConcreteTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 0 assertions) - diff --git a/Tests/TextUI/custom-printer-debug.phpt b/Tests/TextUI/custom-printer-debug.phpt deleted file mode 100644 index 606db42e2ea..00000000000 --- a/Tests/TextUI/custom-printer-debug.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -phpunit -c ../_files/configuration.custom-printer.xml --debug BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Configuration read from %s/configuration.custom-printer.xml - - -Starting test 'BankAccountTest::testBalanceIsInitiallyZero'. -. -Starting test 'BankAccountTest::testBalanceCannotBecomeNegative'. -. -Starting test 'BankAccountTest::testBalanceCannotBecomeNegative2'. -. - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/custom-printer-verbose.phpt b/Tests/TextUI/custom-printer-verbose.phpt deleted file mode 100644 index 5797e9b2492..00000000000 --- a/Tests/TextUI/custom-printer-verbose.phpt +++ /dev/null @@ -1,32 +0,0 @@ ---TEST-- -phpunit -c ../_files/configuration.custom-printer.xml --verbose IncompleteTest ../_files/IncompleteTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Configuration read from %s/configuration.custom-printer.xml - -I - -Time: %s, Memory: %sMb - -There was 1 incomplete test: - -1) IncompleteTest::testIncomplete -Test incomplete - -%s -OK, but incomplete or skipped tests! -Tests: 1, Assertions: 0, Incomplete: 1. diff --git a/Tests/TextUI/dataprovider-log-xml-isolation.phpt b/Tests/TextUI/dataprovider-log-xml-isolation.phpt deleted file mode 100644 index e58c6b595df..00000000000 --- a/Tests/TextUI/dataprovider-log-xml-isolation.phpt +++ /dev/null @@ -1,49 +0,0 @@ ---TEST-- -phpunit --process-isolation --log-junit php://stdout DataProviderTest ../_files/DataProviderTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -..F. - - - - - - - DataProviderTest::testAdd with data set #2 (1, 1, 3) -Failed asserting that 2 matches expected 3. - -%s:%i - - - - - - - - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) DataProviderTest::testAdd with data set #2 (1, 1, 3) -Failed asserting that 2 matches expected 3. -%s:%i - -FAILURES! -Tests: 4, Assertions: 4, Failures: 1. - diff --git a/Tests/TextUI/dataprovider-log-xml.phpt b/Tests/TextUI/dataprovider-log-xml.phpt deleted file mode 100644 index 850e8c4f852..00000000000 --- a/Tests/TextUI/dataprovider-log-xml.phpt +++ /dev/null @@ -1,50 +0,0 @@ ---TEST-- -phpunit --log-junit php://stdout DataProviderTest ../_files/DataProviderTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -..F. - - - - - - - DataProviderTest::testAdd with data set #2 (1, 1, 3) -Failed asserting that 2 matches expected 3. - -%s:%i -%s:%i - - - - - - - - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) DataProviderTest::testAdd with data set #2 (1, 1, 3) -Failed asserting that 2 matches expected 3. -%s:%i -%s:%i - -FAILURES! -Tests: 4, Assertions: 4, Failures: 1. - diff --git a/Tests/TextUI/dataprovider-testdox.phpt b/Tests/TextUI/dataprovider-testdox.phpt deleted file mode 100644 index a9f608420e1..00000000000 --- a/Tests/TextUI/dataprovider-testdox.phpt +++ /dev/null @@ -1,19 +0,0 @@ ---TEST-- -phpunit --testdox DataProviderTest ../_files/DataProviderTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -DataProvider - [ ] Add diff --git a/Tests/TextUI/debug.phpt b/Tests/TextUI/debug.phpt deleted file mode 100644 index 0b2b47deeaf..00000000000 --- a/Tests/TextUI/debug.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -phpunit --debug BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - - -Starting test 'BankAccountTest::testBalanceIsInitiallyZero'. -. -Starting test 'BankAccountTest::testBalanceCannotBecomeNegative'. -. -Starting test 'BankAccountTest::testBalanceCannotBecomeNegative2'. -. - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/default-isolation.phpt b/Tests/TextUI/default-isolation.phpt deleted file mode 100644 index 74e36fd1d8d..00000000000 --- a/Tests/TextUI/default-isolation.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit --process-isolation BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/default.phpt b/Tests/TextUI/default.phpt deleted file mode 100644 index aa7e603137e..00000000000 --- a/Tests/TextUI/default.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -phpunit BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/dependencies-isolation.phpt b/Tests/TextUI/dependencies-isolation.phpt deleted file mode 100644 index e9bb0378017..00000000000 --- a/Tests/TextUI/dependencies-isolation.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -phpunit --process-isolation --verbose DependencyTestSuite ../_files/DependencyTestSuite.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -...FSS - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) DependencyFailureTest::testOne - -%s:%i - -There were 2 skipped tests: - -1) DependencyFailureTest::testTwo -This test depends on "DependencyFailureTest::testOne" to pass. - -%s:%i - -2) DependencyFailureTest::testThree -This test depends on "DependencyFailureTest::testTwo" to pass. - -%s:%i - -FAILURES! -Tests: 4, Assertions: 0, Failures: 1, Skipped: 2. diff --git a/Tests/TextUI/dependencies.phpt b/Tests/TextUI/dependencies.phpt deleted file mode 100644 index c3f383232b8..00000000000 --- a/Tests/TextUI/dependencies.phpt +++ /dev/null @@ -1,42 +0,0 @@ ---TEST-- -phpunit --verbose DependencyTestSuite ../_files/DependencyTestSuite.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -...FSS - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) DependencyFailureTest::testOne - -%s:%i -%s:%i - -There were 2 skipped tests: - -1) DependencyFailureTest::testTwo -This test depends on "DependencyFailureTest::testOne" to pass. - -%s:%i - -2) DependencyFailureTest::testThree -This test depends on "DependencyFailureTest::testTwo" to pass. - -%s:%i - -FAILURES! -Tests: 4, Assertions: 0, Failures: 1, Skipped: 2. diff --git a/Tests/TextUI/dependencies2-isolation.phpt b/Tests/TextUI/dependencies2-isolation.phpt deleted file mode 100644 index 4eb70eabffe..00000000000 --- a/Tests/TextUI/dependencies2-isolation.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --process-isolation StackTest ../_files/StackTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 5 assertions) - diff --git a/Tests/TextUI/dependencies2.phpt b/Tests/TextUI/dependencies2.phpt deleted file mode 100644 index f3eb94ea144..00000000000 --- a/Tests/TextUI/dependencies2.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit StackTest ../_files/StackTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 5 assertions) - diff --git a/Tests/TextUI/dependencies3-isolation.phpt b/Tests/TextUI/dependencies3-isolation.phpt deleted file mode 100644 index a4d116b39af..00000000000 --- a/Tests/TextUI/dependencies3-isolation.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --process-isolation MultiDependencyTest ../_files/MultiDependencyTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 2 assertions) - diff --git a/Tests/TextUI/dependencies3.phpt b/Tests/TextUI/dependencies3.phpt deleted file mode 100644 index 66daf6cb449..00000000000 --- a/Tests/TextUI/dependencies3.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -phpunit MultiDependencyTest ../_files/MultiDependencyTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 2 assertions) diff --git a/Tests/TextUI/empty-testcase.phpt b/Tests/TextUI/empty-testcase.phpt deleted file mode 100644 index 29b3f3aef2f..00000000000 --- a/Tests/TextUI/empty-testcase.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -phpunit EmptyTestCaseTest ../_files/EmptyTestCaseTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -F - -Time: %s, Memory: %sMb - -There was 1 failure: - -1) Warning -No tests found in class "EmptyTestCaseTest". - -%s:%i - -FAILURES! -Tests: 1, Assertions: 0, Failures: 1. diff --git a/Tests/TextUI/exception-stack.phpt b/Tests/TextUI/exception-stack.phpt deleted file mode 100644 index 007bc874560..00000000000 --- a/Tests/TextUI/exception-stack.phpt +++ /dev/null @@ -1,55 +0,0 @@ ---TEST-- -phpunit ExceptionStackTest ../_files/ExceptionStack.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -EE - -Time: %s, Memory: %sMb - -There were 2 errors: - -1) ExceptionStackTest::testPrintingChildException -ExceptionStackTestException: Child exception -message -Failed asserting that two arrays are equal. ---- Expected -+++ Actual -@@ @@ - Array ( -- 0 => 1 -+ 0 => 2 - ) - -%s:%i - -Caused by -%s:%i - -2) ExceptionStackTest::testNestedExceptions -Exception: One - -%s:%i - -Caused by -InvalidArgumentException: Two - -%s:%i - -Caused by -Exception: Three - -%s:%i - -FAILURES! -Tests: 2, Assertions: 1, Errors: 2. - diff --git a/Tests/TextUI/exclude-group-isolation.phpt b/Tests/TextUI/exclude-group-isolation.phpt deleted file mode 100644 index ec931ee1e06..00000000000 --- a/Tests/TextUI/exclude-group-isolation.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -phpunit --process-isolation --exclude-group balanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 2 assertions) diff --git a/Tests/TextUI/exclude-group.phpt b/Tests/TextUI/exclude-group.phpt deleted file mode 100644 index 99514e3a314..00000000000 --- a/Tests/TextUI/exclude-group.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --exclude-group balanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -.. - -Time: %s, Memory: %sMb - -OK (2 tests, 2 assertions) diff --git a/Tests/TextUI/failure-isolation.phpt b/Tests/TextUI/failure-isolation.phpt deleted file mode 100644 index 1a4bb31636b..00000000000 --- a/Tests/TextUI/failure-isolation.phpt +++ /dev/null @@ -1,144 +0,0 @@ ---TEST-- -phpunit --process-isolation FailureTest ../_files/FailureTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -FFFFFFFFFFFFF - -Time: %s, Memory: %sMb - -There were 13 failures: - -1) FailureTest::testAssertArrayEqualsArray -message -Failed asserting that two arrays are equal. ---- Expected -+++ Actual -@@ @@ - Array ( -- 0 => 1 -+ 0 => 2 - ) - -%s:%i - -2) FailureTest::testAssertIntegerEqualsInteger -message -Failed asserting that 2 matches expected 1. - -%s:%i - -3) FailureTest::testAssertObjectEqualsObject -message -Failed asserting that two objects are equal. ---- Expected -+++ Actual -@@ @@ - stdClass Object ( -- 'foo' => 'bar' -+ 'bar' => 'foo' - ) - -%s:%i - -4) FailureTest::testAssertNullEqualsString -message -Failed asserting that 'bar' matches expected null. - -%s:%i - -5) FailureTest::testAssertStringEqualsString -message -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ --'foo' -+'bar' - -%s:%i - -6) FailureTest::testAssertTextEqualsText -message -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ - 'foo --bar -+baz - ' - -%s:%i - -7) FailureTest::testAssertStringMatchesFormat -message -Failed asserting that format description matches text. ---- Expected -+++ Actual -@@ @@ --*%s* -+** - -%s:%i - -8) FailureTest::testAssertNumericEqualsNumeric -message -Failed asserting that 2 matches expected 1. - -%s:%i - -9) FailureTest::testAssertTextSameText -message -Failed asserting that two strings are identical. ---- Expected -+++ Actual -@@ @@ --foo -+bar - -%s:%i - -10) FailureTest::testAssertObjectSameObject -message -Failed asserting that two variables reference the same object. - -%s:%i - -11) FailureTest::testAssertObjectSameNull -message -Failed asserting that null is identical to an object of class "stdClass". - -%s:%i - -12) FailureTest::testAssertFloatSameFloat -message -Failed asserting that 1.5 is identical to 1.0. - -%s:%i - -13) FailureTest::testAssertStringMatchesFormatFile -Failed asserting that format description matches text. ---- Expected -+++ Actual -@@ @@ --FOO -- -+...BAR... - -%s:%i - -FAILURES! -Tests: 13, Assertions: 14, Failures: 13. diff --git a/Tests/TextUI/failure.phpt b/Tests/TextUI/failure.phpt deleted file mode 100644 index 3eda70aa89a..00000000000 --- a/Tests/TextUI/failure.phpt +++ /dev/null @@ -1,144 +0,0 @@ ---TEST-- -phpunit FailureTest ../_files/FailureTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -FFFFFFFFFFFFF - -Time: %s, Memory: %sMb - -There were 13 failures: - -1) FailureTest::testAssertArrayEqualsArray -message -Failed asserting that two arrays are equal. ---- Expected -+++ Actual -@@ @@ - Array ( -- 0 => 1 -+ 0 => 2 - ) - -%s:%i - -2) FailureTest::testAssertIntegerEqualsInteger -message -Failed asserting that 2 matches expected 1. - -%s:%i - -3) FailureTest::testAssertObjectEqualsObject -message -Failed asserting that two objects are equal. ---- Expected -+++ Actual -@@ @@ - stdClass Object ( -- 'foo' => 'bar' -+ 'bar' => 'foo' - ) - -%s:%i - -4) FailureTest::testAssertNullEqualsString -message -Failed asserting that 'bar' matches expected null. - -%s:%i - -5) FailureTest::testAssertStringEqualsString -message -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ --'foo' -+'bar' - -%s:%i - -6) FailureTest::testAssertTextEqualsText -message -Failed asserting that two strings are equal. ---- Expected -+++ Actual -@@ @@ - 'foo --bar -+baz - ' - -%s:%i - -7) FailureTest::testAssertStringMatchesFormat -message -Failed asserting that format description matches text. ---- Expected -+++ Actual -@@ @@ --*%s* -+** - -%s:%i - -8) FailureTest::testAssertNumericEqualsNumeric -message -Failed asserting that 2 matches expected 1. - -%s:%i - -9) FailureTest::testAssertTextSameText -message -Failed asserting that two strings are identical. ---- Expected -+++ Actual -@@ @@ --foo -+bar - -%s:%i - -10) FailureTest::testAssertObjectSameObject -message -Failed asserting that two variables reference the same object. - -%s:%i - -11) FailureTest::testAssertObjectSameNull -message -Failed asserting that null is identical to an object of class "stdClass". - -%s:%i - -12) FailureTest::testAssertFloatSameFloat -message -Failed asserting that 1.5 is identical to 1.0. - -%s:%i - -13) FailureTest::testAssertStringMatchesFormatFile -Failed asserting that format description matches text. ---- Expected -+++ Actual -@@ @@ --FOO -- -+...BAR... - -%s:%i - -FAILURES! -Tests: 13, Assertions: 14, Failures: 13. - diff --git a/Tests/TextUI/fatal-isolation.phpt b/Tests/TextUI/fatal-isolation.phpt deleted file mode 100644 index 5965c079c8c..00000000000 --- a/Tests/TextUI/fatal-isolation.phpt +++ /dev/null @@ -1,29 +0,0 @@ ---TEST-- -phpunit FatalTest ../_files/FatalTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -E - -Time: %s, Memory: %sMb - -There was 1 error: - -1) FatalTest::testFatalError -PHPUnit_Framework_Exception: %s error: Call to undefined function non_existing_function() in %s - - -FAILURES! -Tests: 1, Assertions: 0, Errors: 1. - diff --git a/Tests/TextUI/fatal.phpt b/Tests/TextUI/fatal.phpt deleted file mode 100644 index da1955701bf..00000000000 --- a/Tests/TextUI/fatal.phpt +++ /dev/null @@ -1,17 +0,0 @@ ---TEST-- -phpunit FatalTest ../_files/FatalTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - - -Fatal error: Call to undefined function non_existing_function() in %s diff --git a/Tests/TextUI/filter-class-isolation.phpt b/Tests/TextUI/filter-class-isolation.phpt deleted file mode 100644 index 61c4c9fd20d..00000000000 --- a/Tests/TextUI/filter-class-isolation.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -phpunit --process-isolation --filter BankAccountTest BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/filter-class.phpt b/Tests/TextUI/filter-class.phpt deleted file mode 100644 index 51883c1721a..00000000000 --- a/Tests/TextUI/filter-class.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --filter BankAccountTest BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/filter-method-isolation.phpt b/Tests/TextUI/filter-method-isolation.phpt deleted file mode 100644 index 0dd5aff35b4..00000000000 --- a/Tests/TextUI/filter-method-isolation.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -phpunit --process-isolation --filter testBalanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) diff --git a/Tests/TextUI/filter-method.phpt b/Tests/TextUI/filter-method.phpt deleted file mode 100644 index ccfce148bf7..00000000000 --- a/Tests/TextUI/filter-method.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --filter testBalanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) diff --git a/Tests/TextUI/filter-no-results.phpt b/Tests/TextUI/filter-no-results.phpt deleted file mode 100644 index 301cef001b8..00000000000 --- a/Tests/TextUI/filter-no-results.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --filter testBalanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - - - -Time: %s, Memory: %sMb - -No tests executed! diff --git a/Tests/TextUI/group-isolation.phpt b/Tests/TextUI/group-isolation.phpt deleted file mode 100644 index 1238533f982..00000000000 --- a/Tests/TextUI/group-isolation.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -phpunit --process-isolation --group balanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) diff --git a/Tests/TextUI/group.phpt b/Tests/TextUI/group.phpt deleted file mode 100644 index 0dd1815b9eb..00000000000 --- a/Tests/TextUI/group.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --group balanceIsInitiallyZero BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) diff --git a/Tests/TextUI/help.phpt b/Tests/TextUI/help.phpt deleted file mode 100644 index 7a5ce43539c..00000000000 --- a/Tests/TextUI/help.phpt +++ /dev/null @@ -1,67 +0,0 @@ ---TEST-- -phpunit ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Usage: phpunit [switches] UnitTest [UnitTest.php] - phpunit [switches] - - --log-junit Log test execution in JUnit XML format to file. - --log-tap Log test execution in TAP format to file. - --log-json Log test execution in JSON format. - - --coverage-clover Generate code coverage report in Clover XML format. - --coverage-html Generate code coverage report in HTML format. - --coverage-php Serialize PHP_CodeCoverage object to file. - --coverage-text= Generate code coverage report in text format. - Default to writing to the standard output. - - --testdox-html Write agile documentation in HTML format to file. - --testdox-text Write agile documentation in Text format to file. - - --filter Filter which tests to run. - --testsuite Filter which testsuite to run. - --group ... Only runs tests from the specified group(s). - --exclude-group ... Exclude tests from the specified group(s). - --list-groups List available test groups. - --test-suffix ... Only search for test in files with specified - suffix(es). Default: Test.php,.phpt - - --loader TestSuiteLoader implementation to use. - --printer TestSuiteListener implementation to use. - --repeat Runs the test(s) repeatedly. - - --tap Report test execution progress in TAP format. - --testdox Report test execution progress in TestDox format. - - --colors Use colors in output. - --stderr Write to STDERR instead of STDOUT. - --stop-on-error Stop execution upon first error. - --stop-on-failure Stop execution upon first error or failure. - --stop-on-skipped Stop execution upon first skipped test. - --stop-on-incomplete Stop execution upon first incomplete test. - --strict Run tests in strict mode. - -v|--verbose Output more verbose information. - --debug Display debugging information during test execution. - - --process-isolation Run each test in a separate PHP process. - --no-globals-backup Do not backup and restore $GLOBALS for each test. - --static-backup Backup and restore static attributes for each test. - - --bootstrap A "bootstrap" PHP file that is run before the tests. - -c|--configuration Read configuration from XML file. - --no-configuration Ignore default configuration file (phpunit.xml). - --include-path Prepend PHP's include_path with given path(s). - -d key[=value] Sets a php.ini value. - - -h|--help Prints this usage information. - --version Prints the version and exits. diff --git a/Tests/TextUI/help2.phpt b/Tests/TextUI/help2.phpt deleted file mode 100644 index 9f3d3091765..00000000000 --- a/Tests/TextUI/help2.phpt +++ /dev/null @@ -1,68 +0,0 @@ ---TEST-- -phpunit --help ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Usage: phpunit [switches] UnitTest [UnitTest.php] - phpunit [switches] - - --log-junit Log test execution in JUnit XML format to file. - --log-tap Log test execution in TAP format to file. - --log-json Log test execution in JSON format. - - --coverage-clover Generate code coverage report in Clover XML format. - --coverage-html Generate code coverage report in HTML format. - --coverage-php Serialize PHP_CodeCoverage object to file. - --coverage-text= Generate code coverage report in text format. - Default to writing to the standard output. - - --testdox-html Write agile documentation in HTML format to file. - --testdox-text Write agile documentation in Text format to file. - - --filter Filter which tests to run. - --testsuite Filter which testsuite to run. - --group ... Only runs tests from the specified group(s). - --exclude-group ... Exclude tests from the specified group(s). - --list-groups List available test groups. - --test-suffix ... Only search for test in files with specified - suffix(es). Default: Test.php,.phpt - - --loader TestSuiteLoader implementation to use. - --printer TestSuiteListener implementation to use. - --repeat Runs the test(s) repeatedly. - - --tap Report test execution progress in TAP format. - --testdox Report test execution progress in TestDox format. - - --colors Use colors in output. - --stderr Write to STDERR instead of STDOUT. - --stop-on-error Stop execution upon first error. - --stop-on-failure Stop execution upon first error or failure. - --stop-on-skipped Stop execution upon first skipped test. - --stop-on-incomplete Stop execution upon first incomplete test. - --strict Run tests in strict mode. - -v|--verbose Output more verbose information. - --debug Display debugging information during test execution. - - --process-isolation Run each test in a separate PHP process. - --no-globals-backup Do not backup and restore $GLOBALS for each test. - --static-backup Backup and restore static attributes for each test. - - --bootstrap A "bootstrap" PHP file that is run before the tests. - -c|--configuration Read configuration from XML file. - --no-configuration Ignore default configuration file (phpunit.xml). - --include-path Prepend PHP's include_path with given path(s). - -d key[=value] Sets a php.ini value. - - -h|--help Prints this usage information. - --version Prints the version and exits. diff --git a/Tests/TextUI/ini-isolation.phpt b/Tests/TextUI/ini-isolation.phpt deleted file mode 100644 index b78c2ac4fbe..00000000000 --- a/Tests/TextUI/ini-isolation.phpt +++ /dev/null @@ -1,25 +0,0 @@ ---TEST-- -phpunit --process-isolation -d default_mimetype=application/x-test IniTest ../_files/IniTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -. - -Time: %s, Memory: %sMb - -OK (1 test, 1 assertion) - diff --git a/Tests/TextUI/list-groups.phpt b/Tests/TextUI/list-groups.phpt deleted file mode 100644 index 5b07ed0e573..00000000000 --- a/Tests/TextUI/list-groups.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit --list-groups BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -Available test group(s): - - Sebastian Bergmann - - balanceCannotBecomeNegative - - balanceIsInitiallyZero - - specification diff --git a/Tests/TextUI/log-json.phpt b/Tests/TextUI/log-json.phpt deleted file mode 100644 index 68cac1931d1..00000000000 --- a/Tests/TextUI/log-json.phpt +++ /dev/null @@ -1,72 +0,0 @@ ---TEST-- -phpunit --log-json php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -{ - "event": "suiteStart", - "suite": "BankAccountTest", - "tests": 3 -}{ - "event": "testStart", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceIsInitiallyZero" -}.{ - "event": "test", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceIsInitiallyZero", - "status": "pass", - "time": %f, - "trace": [ - - ], - "message": "", - "output": "" -}{ - "event": "testStart", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceCannotBecomeNegative" -}.{ - "event": "test", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceCannotBecomeNegative", - "status": "pass", - "time": %f, - "trace": [ - - ], - "message": "", - "output": "" -}{ - "event": "testStart", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceCannotBecomeNegative2" -}.{ - "event": "test", - "suite": "BankAccountTest", - "test": "BankAccountTest::testBalanceCannotBecomeNegative2", - "status": "pass", - "time": %f, - "trace": [ - - ], - "message": "", - "output": "" -} - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/log-tap.phpt b/Tests/TextUI/log-tap.phpt deleted file mode 100644 index 0ca03b6cfc0..00000000000 --- a/Tests/TextUI/log-tap.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -phpunit --log-tap php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -TAP version 13 -.ok 1 - BankAccountTest::testBalanceIsInitiallyZero -.ok 2 - BankAccountTest::testBalanceCannotBecomeNegative -.ok 3 - BankAccountTest::testBalanceCannotBecomeNegative2 -1..3 - - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/log-xml.phpt b/Tests/TextUI/log-xml.phpt deleted file mode 100644 index 91e591037d7..00000000000 --- a/Tests/TextUI/log-xml.phpt +++ /dev/null @@ -1,31 +0,0 @@ ---TEST-- -phpunit --log-junit php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - - - - - - - - - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/repeat.phpt b/Tests/TextUI/repeat.phpt deleted file mode 100644 index 6a29a84111e..00000000000 --- a/Tests/TextUI/repeat.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --repeat 3 BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -......... - -Time: %s, Memory: %sMb - -OK (9 tests, 9 assertions) diff --git a/Tests/TextUI/strict-incomplete.phpt b/Tests/TextUI/strict-incomplete.phpt deleted file mode 100644 index 3b2f58c0444..00000000000 --- a/Tests/TextUI/strict-incomplete.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --strict IncompleteTest ../_files/IncompleteTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -I - -Time: %s, Memory: %sMb - -OK, but incomplete or skipped tests! -Tests: 1, Assertions: 0, Incomplete: 1. diff --git a/Tests/TextUI/strict-isolation.phpt b/Tests/TextUI/strict-isolation.phpt deleted file mode 100644 index 125febe3528..00000000000 --- a/Tests/TextUI/strict-isolation.phpt +++ /dev/null @@ -1,24 +0,0 @@ ---TEST-- -phpunit --strict --process-isolation IncompleteTest ../_files/IncompleteTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -I - -Time: %s, Memory: %sMb - -OK, but incomplete or skipped tests! -Tests: 1, Assertions: 0, Incomplete: 1. diff --git a/Tests/TextUI/strict.phpt b/Tests/TextUI/strict.phpt deleted file mode 100644 index 98b3583c655..00000000000 --- a/Tests/TextUI/strict.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --strict NothingTest ../_files/NothingTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -I - -Time: %s, Memory: %sMb - -OK, but incomplete or skipped tests! -Tests: 1, Assertions: 0, Incomplete: 1. diff --git a/Tests/TextUI/tap.phpt b/Tests/TextUI/tap.phpt deleted file mode 100644 index f53708050ac..00000000000 --- a/Tests/TextUI/tap.phpt +++ /dev/null @@ -1,20 +0,0 @@ ---TEST-- -phpunit --tap BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -TAP version 13 -ok 1 - BankAccountTest::testBalanceIsInitiallyZero -ok 2 - BankAccountTest::testBalanceCannotBecomeNegative -ok 3 - BankAccountTest::testBalanceCannotBecomeNegative2 -1..3 diff --git a/Tests/TextUI/test-suffix-multiple.phpt b/Tests/TextUI/test-suffix-multiple.phpt deleted file mode 100644 index bdde18efbb4..00000000000 --- a/Tests/TextUI/test-suffix-multiple.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit --test-suffix .test.php,.my.php ../_files/ ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -..... - -Time: %s, Memory: %sMb - -OK (5 tests, 3 assertions) diff --git a/Tests/TextUI/test-suffix-single.phpt b/Tests/TextUI/test-suffix-single.phpt deleted file mode 100644 index b91e51c6714..00000000000 --- a/Tests/TextUI/test-suffix-single.phpt +++ /dev/null @@ -1,22 +0,0 @@ ---TEST-- -phpunit --test-suffix .test.php ../_files/ ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -... - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/testdox-html.phpt b/Tests/TextUI/testdox-html.phpt deleted file mode 100644 index f7e718a0c49..00000000000 --- a/Tests/TextUI/testdox-html.phpt +++ /dev/null @@ -1,23 +0,0 @@ ---TEST-- -phpunit --testdox-html php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -

BankAccount

    ...
  • Balance is initially zero
  • Balance cannot become negative
- -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/testdox-text.phpt b/Tests/TextUI/testdox-text.phpt deleted file mode 100644 index eea0bba0f2f..00000000000 --- a/Tests/TextUI/testdox-text.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -phpunit --testdox-text php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -BankAccount -... [x] Balance is initially zero - [x] Balance cannot become negative - - - -Time: %s, Memory: %sMb - -OK (3 tests, 3 assertions) diff --git a/Tests/TextUI/testdox.phpt b/Tests/TextUI/testdox.phpt deleted file mode 100644 index 0d24c0e2213..00000000000 --- a/Tests/TextUI/testdox.phpt +++ /dev/null @@ -1,21 +0,0 @@ ---TEST-- -phpunit --testdox php://stdout BankAccountTest ../_files/BankAccountTest.php ---FILE-- - ---EXPECTF-- -PHPUnit %s by Sebastian Bergmann. - -BankAccount - [x] Balance is initially zero - [x] Balance cannot become negative - diff --git a/Tests/Util/ConfigurationTest.php b/Tests/Util/ConfigurationTest.php deleted file mode 100644 index 7726496ef4f..00000000000 --- a/Tests/Util/ConfigurationTest.php +++ /dev/null @@ -1,390 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class Util_ConfigurationTest extends PHPUnit_Framework_TestCase -{ - protected $configuration; - - protected function setUp() - { - $this->configuration = PHPUnit_Util_Configuration::getInstance( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'configuration.xml' - ); - } - - /** - * @expectedException PHPUnit_Framework_Exception - */ - public function testExceptionIsThrownForNotExistingConfigurationFile() - { - PHPUnit_Util_Configuration::getInstance('not_existing_file.xml'); - } - - public function testFilterConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 'blacklist' => - array( - 'include' => - array( - 'directory' => - array( - 0 => - array( - 'path' => '/path/to/files', - 'prefix' => '', - 'suffix' => '.php', - 'group' => 'DEFAULT' - ), - ), - 'file' => - array( - 0 => '/path/to/file', - ), - ), - 'exclude' => - array( - 'directory' => - array( - 0 => - array( - 'path' => '/path/to/files', - 'prefix' => '', - 'suffix' => '.php', - 'group' => 'DEFAULT' - ), - ), - 'file' => - array( - 0 => '/path/to/file', - ), - ), - ), - 'whitelist' => - array( - 'addUncoveredFilesFromWhitelist' => TRUE, - 'processUncoveredFilesFromWhitelist' => FALSE, - 'include' => - array( - 'directory' => - array( - 0 => - array( - 'path' => '/path/to/files', - 'prefix' => '', - 'suffix' => '.php', - 'group' => 'DEFAULT' - ), - ), - 'file' => - array( - 0 => '/path/to/file', - ), - ), - 'exclude' => - array( - 'directory' => - array( - 0 => - array( - 'path' => '/path/to/files', - 'prefix' => '', - 'suffix' => '.php', - 'group' => 'DEFAULT' - ), - ), - 'file' => - array( - 0 => '/path/to/file', - ), - ), - ), - ), - $this->configuration->getFilterConfiguration() - ); - } - - public function testGroupConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 'include' => - array( - 0 => 'name', - ), - 'exclude' => - array( - 0 => 'name', - ), - ), - $this->configuration->getGroupConfiguration() - ); - } - - public function testListenerConfigurationIsReadCorrectly() - { - $dir = __DIR__; - $includePath = ini_get('include_path'); - - ini_set('include_path', $dir . PATH_SEPARATOR . $includePath); - - $this->assertEquals( - array( - 0 => - array( - 'class' => 'MyListener', - 'file' => '/optional/path/to/MyListener.php', - 'arguments' => - array( - 0 => - array( - 0 => 'Sebastian', - ), - 1 => 22, - 2 => 'April', - 3 => 19.78, - 4 => NULL, - 5 => new stdClass, - 6 => dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'MyTestFile.php', - 7 => dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'MyRelativePath', - ), - ), - array( - 'class' => 'IncludePathListener', - 'file' => __FILE__, - 'arguments' => array() - ), - array( - 'class' => 'CompactArgumentsListener', - 'file' => '/CompactArgumentsListener.php', - 'arguments' => - array( - 0 => 42 - ), - ), - ), - $this->configuration->getListenerConfiguration() - ); - - ini_set('include_path', $includePath); - } - - public function testLoggingConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 'charset' => 'UTF-8', - 'lowUpperBound' => '35', - 'highLowerBound' => '70', - 'highlight' => FALSE, - 'coverage-html' => '/tmp/report', - 'coverage-clover' => '/tmp/clover.xml', - 'json' => '/tmp/logfile.json', - 'plain' => '/tmp/logfile.txt', - 'tap' => '/tmp/logfile.tap', - 'logIncompleteSkipped' => FALSE, - 'junit' => '/tmp/logfile.xml', - 'testdox-html' => '/tmp/testdox.html', - 'testdox-text' => '/tmp/testdox.txt', - ), - $this->configuration->getLoggingConfiguration() - ); - } - - public function testPHPConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 'include_path' => - array( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . '.', - '/path/to/lib' - ), - 'ini'=> array('foo' => 'bar'), - 'const'=> array('FOO' => FALSE, 'BAR' => TRUE), - 'var'=> array('foo' => FALSE), - 'env'=> array('foo' => TRUE), - 'post'=> array('foo' => 'bar'), - 'get'=> array('foo' => 'bar'), - 'cookie'=> array('foo' => 'bar'), - 'server'=> array('foo' => 'bar'), - 'files'=> array('foo' => 'bar'), - 'request'=> array('foo' => 'bar'), - ), - $this->configuration->getPHPConfiguration() - ); - } - - /** - * @backupGlobals enabled - */ - public function testPHPConfigurationIsHandledCorrectly() - { - $this->configuration->handlePHPConfiguration(); - - $path = dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . '.' . PATH_SEPARATOR . '/path/to/lib'; - $this->assertStringStartsWith($path, ini_get('include_path')); - $this->assertEquals(FALSE, FOO); - $this->assertEquals(TRUE, BAR); - $this->assertEquals(FALSE, $GLOBALS['foo']); - $this->assertEquals(TRUE, $_ENV['foo']); - $this->assertEquals(TRUE, getenv('foo')); - $this->assertEquals('bar', $_POST['foo']); - $this->assertEquals('bar', $_GET['foo']); - $this->assertEquals('bar', $_COOKIE['foo']); - $this->assertEquals('bar', $_SERVER['foo']); - $this->assertEquals('bar', $_FILES['foo']); - $this->assertEquals('bar', $_REQUEST['foo']); - } - - public function testPHPUnitConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 'backupGlobals' => TRUE, - 'backupStaticAttributes' => FALSE, - 'bootstrap' => '/path/to/bootstrap.php', - 'cacheTokens' => FALSE, - 'colors' => FALSE, - 'convertErrorsToExceptions' => TRUE, - 'convertNoticesToExceptions' => TRUE, - 'convertWarningsToExceptions' => TRUE, - 'forceCoversAnnotation' => FALSE, - 'mapTestClassNameToCoveredClassName' => FALSE, - 'printerClass' => 'PHPUnit_TextUI_ResultPrinter', - 'stopOnFailure' => FALSE, - 'strict' => FALSE, - 'testSuiteLoaderClass' => 'PHPUnit_Runner_StandardTestSuiteLoader', - 'verbose' => FALSE, - 'timeoutForSmallTests' => 1, - 'timeoutForMediumTests' => 10, - 'timeoutForLargeTests' => 60 - ), - $this->configuration->getPHPUnitConfiguration() - ); - } - - public function testSeleniumBrowserConfigurationIsReadCorrectly() - { - $this->assertEquals( - array( - 0 => - array( - 'name' => 'Firefox on Linux', - 'browser' => '*firefox /usr/lib/firefox/firefox-bin', - 'host' => 'my.linux.box', - 'port' => 4444, - 'timeout' => 30000, - ), - ), - $this->configuration->getSeleniumBrowserConfiguration() - ); - } - - public function testXincludeInConfiguration() - { - $configurationWithXinclude = PHPUnit_Util_Configuration::getInstance( - dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'configuration_xinclude.xml' - ); - - $this->assertConfigurationEquals( - $this->configuration, - $configurationWithXinclude - ); - } - - /** - * Asserts that the values in $actualConfiguration equal $expectedConfiguration. - * - * @param PHPUnit_Util_Configuration $expectedConfiguration - * @param PHPUnit_Util_Configuration $actualConfiguration - * @return void - */ - protected function assertConfigurationEquals( PHPUnit_Util_Configuration $expectedConfiguration, PHPUnit_Util_Configuration $actualConfiguration ) - { - $this->assertEquals( - $expectedConfiguration->getFilterConfiguration(), - $actualConfiguration->getFilterConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getGroupConfiguration(), - $actualConfiguration->getGroupConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getListenerConfiguration(), - $actualConfiguration->getListenerConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getLoggingConfiguration(), - $actualConfiguration->getLoggingConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getPHPConfiguration(), - $actualConfiguration->getPHPConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getPHPUnitConfiguration(), - $actualConfiguration->getPHPUnitConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getSeleniumBrowserConfiguration(), - $actualConfiguration->getSeleniumBrowserConfiguration() - ); - $this->assertEquals( - $expectedConfiguration->getTestSuiteConfiguration(), - $actualConfiguration->getTestSuiteConfiguration() - ); - } -} diff --git a/Tests/Util/TestDox/NamePrettifierTest.php b/Tests/Util/TestDox/NamePrettifierTest.php deleted file mode 100644 index f87ff769c90..00000000000 --- a/Tests/Util/TestDox/NamePrettifierTest.php +++ /dev/null @@ -1,108 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.1.0 - */ -class Util_TestDox_NamePrettifierTest extends PHPUnit_Framework_TestCase -{ - protected $namePrettifier; - - protected function setUp() - { - $this->namePrettifier = new PHPUnit_Util_TestDox_NamePrettifier; - } - - public function testTitleHasSensibleDefaults() - { - $this->assertEquals('Foo', $this->namePrettifier->prettifyTestClass('FooTest')); - $this->assertEquals('Foo', $this->namePrettifier->prettifyTestClass('TestFoo')); - $this->assertEquals('Foo', $this->namePrettifier->prettifyTestClass('TestFooTest')); - } - - public function testCaterForUserDefinedSuffix() - { - $this->namePrettifier->setSuffix('TestCase'); - $this->namePrettifier->setPrefix(NULL); - - $this->assertEquals('Foo', $this->namePrettifier->prettifyTestClass('FooTestCase')); - $this->assertEquals('TestFoo', $this->namePrettifier->prettifyTestClass('TestFoo')); - $this->assertEquals('FooTest', $this->namePrettifier->prettifyTestClass('FooTest')); - } - - public function testCaterForUserDefinedPrefix() - { - $this->namePrettifier->setSuffix(NULL); - $this->namePrettifier->setPrefix('XXX'); - - $this->assertEquals('Foo', $this->namePrettifier->prettifyTestClass('XXXFoo')); - $this->assertEquals('TestXXX', $this->namePrettifier->prettifyTestClass('TestXXX')); - $this->assertEquals('XXX', $this->namePrettifier->prettifyTestClass('XXXXXX')); - } - - public function testTestNameIsConvertedToASentence() - { - $this->assertEquals('This is a test', $this->namePrettifier->prettifyTestMethod('testThisIsATest')); - $this->assertEquals('This is a test', $this->namePrettifier->prettifyTestMethod('testThisIsATest2')); - $this->assertEquals('this is a test', $this->namePrettifier->prettifyTestMethod('this_is_a_test')); - $this->assertEquals('Foo for bar is 0', $this->namePrettifier->prettifyTestMethod('testFooForBarIs0')); - $this->assertEquals('Foo for baz is 1', $this->namePrettifier->prettifyTestMethod('testFooForBazIs1')); - } - - /** - * @ticket 224 - */ - public function testTestNameIsNotGroupedWhenNotInSequence() - { - $this->assertEquals('Sets redirect header on 301', $this->namePrettifier->prettifyTestMethod('testSetsRedirectHeaderOn301')); - $this->assertEquals('Sets redirect header on 302', $this->namePrettifier->prettifyTestMethod('testSetsRedirectHeaderOn302')); - } -} diff --git a/Tests/Util/TestTest.php b/Tests/Util/TestTest.php deleted file mode 100644 index a65dd14527e..00000000000 --- a/Tests/Util/TestTest.php +++ /dev/null @@ -1,239 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.6 - */ - -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'ExceptionNamespaceTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'RequirementsTest.php'; -require_once dirname(__DIR__) . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR . 'RequirementsClassDocBlockTest.php'; - -/** - * - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.6 - */ -class Util_TestTest extends PHPUnit_Framework_TestCase -{ - public function testGetExpectedException() - { - $this->assertSame( - array('class' => 'FooBarBaz', 'code' => NULL, 'message' => ''), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testOne') - ); - - $this->assertSame( - array('class' => 'Foo_Bar_Baz', 'code' => NULL, 'message' => ''), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testTwo') - ); - - $this->assertSame( - array('class' => 'Foo\Bar\Baz', 'code' => NULL, 'message' => ''), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testThree') - ); - - $this->assertSame( - array('class' => 'ほげ', 'code' => NULL, 'message' => ''), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testFour') - ); - - $this->assertSame( - array('class' => 'Class', 'code' => 1234, 'message' => 'Message'), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testFive') - ); - - $this->assertSame( - array('class' => 'Class', 'code' => 1234, 'message' => 'Message'), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testSix') - ); - - $this->assertSame( - array('class' => 'Class', 'code' => 'ExceptionCode', 'message' => 'Message'), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testSeven') - ); - - $this->assertSame( - array('class' => 'Class', 'code' => 0, 'message' => 'Message'), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testEight') - ); - $this->assertSame( - array('class' => 'Class', 'code' => ExceptionTest::ERROR_CODE, 'message' => ExceptionTest::ERROR_MESSAGE), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testNine') - ); - $this->assertSame( - array('class' => 'Class', 'code' => My\Space\ExceptionNamespaceTest::ERROR_CODE, 'message' => My\Space\ExceptionNamespaceTest::ERROR_MESSAGE), - PHPUnit_Util_Test::getExpectedException('My\Space\ExceptionNamespaceTest', 'testConstants') - ); - // Ensure the Class::CONST expression is only evaluated when the constant really exists - $this->assertSame( - array('class' => 'Class', 'code' => 'ExceptionTest::UNKNOWN_CODE_CONSTANT', 'message' => 'ExceptionTest::UNKNOWN_MESSAGE_CONSTANT'), - PHPUnit_Util_Test::getExpectedException('ExceptionTest', 'testUnknownConstants') - ); - $this->assertSame( - array('class' => 'Class', 'code' => 'My\Space\ExceptionNamespaceTest::UNKNOWN_CODE_CONSTANT', 'message' => 'My\Space\ExceptionNamespaceTest::UNKNOWN_MESSAGE_CONSTANT'), - PHPUnit_Util_Test::getExpectedException('My\Space\ExceptionNamespaceTest', 'testUnknownConstants') - ); - } - - public function provideRequirements() - { - return array( - array('testOne', array()), - array('testTwo', array('PHPUnit' => '1.0')), - array('testThree', array('PHP' => '2.0')), - array('testFour', array('PHPUnit'=>'2.0', 'PHP' => '1.0')), - array('testFive', array('PHP' => '5.4.0RC6')), - array('testSix', array('PHP' => '5.4.0-alpha1')), - array('testSeven', array('PHP' => '5.4.0beta2')), - array('testEight', array('PHP' => '5.4-dev')), - array('testNine', array('functions' => array('testFunc'))), - array('testTen', array('extensions' => array('testExt'))), - array('testEleven', array('OS' => '/Linux/i')), - array( - 'testAllPossibleRequirements', - array( - 'PHP' => '99-dev', - 'PHPUnit' => '9-dev', - 'OS' => '/DOESNOTEXIST/i', - 'functions' => array( - 'testFuncOne', - 'testFuncTwo', - ), - 'extensions' => array( - 'testExtOne', - 'testExtTwo', - ) - ) - ) - ); - } - - /** - * @dataProvider provideRequirements - */ - public function testGetRequirements($test, $result) - { - $this->assertEquals( - $result, - PHPUnit_Util_Test::getRequirements('RequirementsTest', $test) - ); - } - - public function testGetRequirementsMergesClassAndMethodDocBlocks() - { - $expectedAnnotations = array( - 'PHP' => '5.4', - 'PHPUnit' => '3.7', - 'OS' => '/WINNT/i', - 'functions' => array( - 'testFuncClass', - 'testFuncMethod', - ), - 'extensions' => array( - 'testExtClass', - 'testExtMethod', - ) - ); - - $this->assertEquals( - $expectedAnnotations, - PHPUnit_Util_Test::getRequirements('RequirementsClassDocBlockTest', 'testMethod') - ); - } - - public function testGetProvidedDataRegEx() - { - $result = preg_match(PHPUnit_Util_Test::REGEX_DATA_PROVIDER, '@dataProvider method', $matches); - $this->assertEquals(1, $result); - $this->assertEquals('method', $matches[1]); - - $result = preg_match(PHPUnit_Util_Test::REGEX_DATA_PROVIDER, '@dataProvider class::method', $matches); - $this->assertEquals(1, $result); - $this->assertEquals('class::method', $matches[1]); - - $result = preg_match(PHPUnit_Util_Test::REGEX_DATA_PROVIDER, '@dataProvider namespace\class::method', $matches); - $this->assertEquals(1, $result); - $this->assertEquals('namespace\class::method', $matches[1]); - - $result = preg_match(PHPUnit_Util_Test::REGEX_DATA_PROVIDER, '@dataProvider namespace\namespace\class::method', $matches); - $this->assertEquals(1, $result); - $this->assertEquals('namespace\namespace\class::method', $matches[1]); - - $result = preg_match(PHPUnit_Util_Test::REGEX_DATA_PROVIDER, '@dataProvider メソッド', $matches); - $this->assertEquals(1, $result); - $this->assertEquals('メソッド', $matches[1]); - } - - public function testParseAnnotation() - { - $this->assertEquals( - array('Foo', 'ほげ'), - PHPUnit_Util_Test::getDependencies(get_class($this), 'methodForTestParseAnnotation') - ); - } - - /** - * @depends Foo - * @depends ほげ - */ - public function methodForTestParseAnnotation() - { - } - - public function testParseAnnotationThatIsOnlyOneLine() - { - $this->assertEquals( - array('Bar'), - PHPUnit_Util_Test::getDependencies(get_class($this), 'methodForTestParseAnnotationThatIsOnlyOneLine') - ); - } - - /** @depends Bar */ - public function methodForTestParseAnnotationThatIsOnlyOneLine() - { - } -} diff --git a/Tests/Util/XMLTest.php b/Tests/Util/XMLTest.php deleted file mode 100644 index 404fe8c32ea..00000000000 --- a/Tests/Util/XMLTest.php +++ /dev/null @@ -1,358 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Mike Naberezny - * @author Derek DeVries - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.3.0 - */ - -/** - * - * - * @package PHPUnit - * @author Mike Naberezny - * @author Derek DeVries - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.3.0 - */ -class Util_XMLTest extends PHPUnit_Framework_TestCase -{ - public function testAssertValidKeysValidKeys() - { - $options = array('testA' => 1, 'testB' => 2, 'testC' => 3); - $valid = array('testA', 'testB', 'testC'); - $expected = array('testA' => 1, 'testB' => 2, 'testC' => 3); - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - - $this->assertEquals($expected, $validated); - } - - public function testAssertValidKeysValidKeysEmpty() - { - $options = array('testA' => 1, 'testB' => 2); - $valid = array('testA', 'testB', 'testC'); - $expected = array('testA' => 1, 'testB' => 2, 'testC' => NULL); - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - - $this->assertEquals($expected, $validated); - } - - public function testAssertValidKeysDefaultValuesA() - { - $options = array('testA' => 1, 'testB' => 2); - $valid = array('testA' => 23, 'testB' => 24, 'testC' => 25); - $expected = array('testA' => 1, 'testB' => 2, 'testC' => 25); - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - - $this->assertEquals($expected, $validated); - } - - public function testAssertValidKeysDefaultValuesB() - { - $options = array(); - $valid = array('testA' => 23, 'testB' => 24, 'testC' => 25); - $expected = array('testA' => 23, 'testB' => 24, 'testC' => 25); - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - - $this->assertEquals($expected, $validated); - } - - public function testAssertValidKeysInvalidKey() - { - $options = array('testA' => 1, 'testB' => 2, 'testD' => 3); - $valid = array('testA', 'testB', 'testC'); - - try { - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - $this->fail(); - } - - catch (PHPUnit_Framework_Exception $e) { - $this->assertEquals('Unknown key(s): testD', $e->getMessage()); - } - } - - public function testAssertValidKeysInvalidKeys() - { - $options = array('testA' => 1, 'testD' => 2, 'testE' => 3); - $valid = array('testA', 'testB', 'testC'); - - try { - $validated = PHPUnit_Util_XML::assertValidKeys($options, $valid); - $this->fail(); - } - - catch (PHPUnit_Framework_Exception $e) { - $this->assertEquals('Unknown key(s): testD, testE', $e->getMessage()); - } - } - - public function testConvertAssertSelect() - { - $selector = 'div#folder.open a[href="http://www.xerox.com/"][title="xerox"].selected.big > span'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', - 'id' => 'folder', - 'class' => 'open', - 'descendant' => array('tag' => 'a', - 'class' => 'selected big', - 'attributes' => array('href' => 'http://www.xerox.com/', - 'title' => 'xerox'), - 'child' => array('tag' => 'span'))); - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectElt() - { - $selector = 'div'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertClass() - { - $selector = '.foo'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('class' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertId() - { - $selector = '#foo'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('id' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertAttribute() - { - $selector = '[foo="bar"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('attributes' => array('foo' => 'bar')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertAttributeSpaces() - { - $selector = '[foo="bar baz"] div[value="foo bar"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('attributes' => array('foo' => 'bar baz'), - 'descendant' => array('tag' => 'div', - 'attributes' => array('value' => 'foo bar'))); - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertAttributeMultipleSpaces() - { - $selector = '[foo="bar baz"] div[value="foo bar baz"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('attributes' => array('foo' => 'bar baz'), - 'descendant' => array('tag' => 'div', - 'attributes' => array('value' => 'foo bar baz'))); - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltClass() - { - $selector = 'div.foo'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'class' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltId() - { - $selector = 'div#foo'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'id' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltAttrEqual() - { - $selector = 'div[foo="bar"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'attributes' => array('foo' => 'bar')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltMultiAttrEqual() - { - $selector = 'div[foo="bar"][baz="fob"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'attributes' => array('foo' => 'bar', 'baz' => 'fob')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltAttrHasOne() - { - $selector = 'div[foo~="bar"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'attributes' => array('foo' => 'regexp:/.*\bbar\b.*/')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltAttrContains() - { - $selector = 'div[foo*="bar"]'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'attributes' => array('foo' => 'regexp:/.*bar.*/')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltChild() - { - $selector = 'div > a'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'child' => array('tag' => 'a')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectEltDescendant() - { - $selector = 'div a'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector); - $tag = array('tag' => 'div', 'descendant' => array('tag' => 'a')); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectContent() - { - $selector = '#foo'; - $content = 'div contents'; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector, $content); - $tag = array('id' => 'foo', 'content' => 'div contents'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectTrue() - { - $selector = '#foo'; - $content = TRUE; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector, $content); - $tag = array('id' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertSelectFalse() - { - $selector = '#foo'; - $content = FALSE; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector, $content); - $tag = array('id' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertNumber() - { - $selector = '.foo'; - $content = 3; - $converted = PHPUnit_Util_XML::convertSelectToTag($selector, $content); - $tag = array('class' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - public function testConvertAssertRange() - { - $selector = '#foo'; - $content = array('greater_than' => 5, 'less_than' => 10); - $converted = PHPUnit_Util_XML::convertSelectToTag($selector, $content); - $tag = array('id' => 'foo'); - - $this->assertEquals($tag, $converted); - } - - /** - * @dataProvider charProvider - */ - public function testPrepareString($char) - { - $e = null; - - $escapedString = PHPUnit_Util_XML::prepareString($char); - $xml = "$escapedString"; - $dom = new DomDocument('1.0', 'UTF-8'); - - try { - $dom->loadXML($xml); - } - - catch (Exception $e) { - } - - $this->assertNull($e, sprintf( - 'PHPUnit_Util_XML::prepareString("\x%02x") should not crash DomDocument', - ord($char) - )); - } - - public function charProvider() - { - $data = array(); - - for ($i = 0; $i < 256; $i++) { - $data[] = array(chr($i)); - } - - return $data; - } -} diff --git a/Tests/_files/AbstractTest.php b/Tests/_files/AbstractTest.php deleted file mode 100644 index 556e7dbc0e3..00000000000 --- a/Tests/_files/AbstractTest.php +++ /dev/null @@ -1,7 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * An author. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class Author -{ - // the order of properties is important for testing the cycle! - public $books = array(); - - private $name = ''; - - public function __construct($name) - { - $this->name = $name; - } -} \ No newline at end of file diff --git a/Tests/_files/BankAccount.php b/Tests/_files/BankAccount.php deleted file mode 100644 index 2560dd2359a..00000000000 --- a/Tests/_files/BankAccount.php +++ /dev/null @@ -1,116 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -class BankAccountException extends RuntimeException {} - -/** - * A bank account. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.3.0 - */ -class BankAccount -{ - /** - * The bank account's balance. - * - * @var float - */ - protected $balance = 0; - - /** - * Returns the bank account's balance. - * - * @return float - */ - public function getBalance() - { - return $this->balance; - } - - /** - * Sets the bank account's balance. - * - * @param float $balance - * @throws BankAccountException - */ - protected function setBalance($balance) - { - if ($balance >= 0) { - $this->balance = $balance; - } else { - throw new BankAccountException; - } - } - - /** - * Deposits an amount of money to the bank account. - * - * @param float $balance - * @throws BankAccountException - */ - public function depositMoney($balance) - { - $this->setBalance($this->getBalance() + $balance); - - return $this->getBalance(); - } - - /** - * Withdraws an amount of money from the bank account. - * - * @param float $balance - * @throws BankAccountException - */ - public function withdrawMoney($balance) - { - $this->setBalance($this->getBalance() - $balance); - - return $this->getBalance(); - } -} diff --git a/Tests/_files/BankAccountTest.php b/Tests/_files/BankAccountTest.php deleted file mode 100644 index f4cfd783e07..00000000000 --- a/Tests/_files/BankAccountTest.php +++ /dev/null @@ -1,133 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -require_once 'PHPUnit/Framework/TestCase.php'; -require_once 'BankAccount.php'; - -/** - * Tests for the BankAccount class. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.3.0 - */ -class BankAccountTest extends PHPUnit_Framework_TestCase -{ - protected $ba; - - protected function setUp() - { - $this->ba = new BankAccount; - } - - /** - * @covers BankAccount::getBalance - * @group balanceIsInitiallyZero - * @group specification - */ - public function testBalanceIsInitiallyZero() - { - $this->assertEquals(0, $this->ba->getBalance()); - } - - /** - * @covers BankAccount::withdrawMoney - * @group balanceCannotBecomeNegative - * @group specification - */ - public function testBalanceCannotBecomeNegative() - { - try { - $this->ba->withdrawMoney(1); - } - - catch (BankAccountException $e) { - $this->assertEquals(0, $this->ba->getBalance()); - - return; - } - - $this->fail(); - } - - /** - * @covers BankAccount::depositMoney - * @group balanceCannotBecomeNegative - * @group specification - */ - public function testBalanceCannotBecomeNegative2() - { - try { - $this->ba->depositMoney(-1); - } - - catch (BankAccountException $e) { - $this->assertEquals(0, $this->ba->getBalance()); - - return; - } - - $this->fail(); - } - - /** - * @covers BankAccount::getBalance - * @covers BankAccount::depositMoney - * @covers BankAccount::withdrawMoney - * @group balanceCannotBecomeNegative - */ - /* - public function testDepositingAndWithdrawingMoneyWorks() - { - $this->assertEquals(0, $this->ba->getBalance()); - $this->ba->depositMoney(1); - $this->assertEquals(1, $this->ba->getBalance()); - $this->ba->withdrawMoney(1); - $this->assertEquals(0, $this->ba->getBalance()); - } - */ -} diff --git a/Tests/_files/BankAccountTest.test.php b/Tests/_files/BankAccountTest.test.php deleted file mode 100644 index 18bda4ff44d..00000000000 --- a/Tests/_files/BankAccountTest.test.php +++ /dev/null @@ -1,133 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 2.3.0 - */ - -require_once 'PHPUnit/Framework/TestCase.php'; -require_once 'BankAccount.php'; - -/** - * Tests for the BankAccount class. - * - * @package PHPUnit - * @author Sebastian Bergmann - * @copyright 2002-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 2.3.0 - */ -class BankAccountWithCustomExtensionTest extends PHPUnit_Framework_TestCase -{ - protected $ba; - - protected function setUp() - { - $this->ba = new BankAccount; - } - - /** - * @covers BankAccount::getBalance - * @group balanceIsInitiallyZero - * @group specification - */ - public function testBalanceIsInitiallyZero() - { - $this->assertEquals(0, $this->ba->getBalance()); - } - - /** - * @covers BankAccount::withdrawMoney - * @group balanceCannotBecomeNegative - * @group specification - */ - public function testBalanceCannotBecomeNegative() - { - try { - $this->ba->withdrawMoney(1); - } - - catch (BankAccountException $e) { - $this->assertEquals(0, $this->ba->getBalance()); - - return; - } - - $this->fail(); - } - - /** - * @covers BankAccount::depositMoney - * @group balanceCannotBecomeNegative - * @group specification - */ - public function testBalanceCannotBecomeNegative2() - { - try { - $this->ba->depositMoney(-1); - } - - catch (BankAccountException $e) { - $this->assertEquals(0, $this->ba->getBalance()); - - return; - } - - $this->fail(); - } - - /** - * @covers BankAccount::getBalance - * @covers BankAccount::depositMoney - * @covers BankAccount::withdrawMoney - * @group balanceCannotBecomeNegative - */ - /* - public function testDepositingAndWithdrawingMoneyWorks() - { - $this->assertEquals(0, $this->ba->getBalance()); - $this->ba->depositMoney(1); - $this->assertEquals(1, $this->ba->getBalance()); - $this->ba->withdrawMoney(1); - $this->assertEquals(0, $this->ba->getBalance()); - } - */ -} diff --git a/Tests/_files/BaseTestListenerSample.php b/Tests/_files/BaseTestListenerSample.php deleted file mode 100644 index f90f30750fb..00000000000 --- a/Tests/_files/BaseTestListenerSample.php +++ /dev/null @@ -1,11 +0,0 @@ -endCount++; - } -} \ No newline at end of file diff --git a/Tests/_files/Book.php b/Tests/_files/Book.php deleted file mode 100644 index b515a6ca5b5..00000000000 --- a/Tests/_files/Book.php +++ /dev/null @@ -1,59 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * A book. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class Book -{ - // the order of properties is important for testing the cycle! - public $author = NULL; -} diff --git a/Tests/_files/Calculator.php b/Tests/_files/Calculator.php deleted file mode 100644 index e269bd6ca0b..00000000000 --- a/Tests/_files/Calculator.php +++ /dev/null @@ -1,14 +0,0 @@ -assertTrue(TRUE); - } - -} diff --git a/Tests/_files/ClassWithNonPublicAttributes.php b/Tests/_files/ClassWithNonPublicAttributes.php deleted file mode 100644 index bb979e75014..00000000000 --- a/Tests/_files/ClassWithNonPublicAttributes.php +++ /dev/null @@ -1,29 +0,0 @@ -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since File available since Release 3.6.0 - */ - -/** - * A class with a __toString() method. - * - * @package PHPUnit - * @author Bernhard Schussek - * @copyright 2001-2013 Sebastian Bergmann - * @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License - * @link http://www.phpunit.de/ - * @since Class available since Release 3.6.0 - */ -class ClassWithToString -{ - public function __toString() - { - return 'string representation'; - } -} \ No newline at end of file diff --git a/Tests/_files/ConcreteTest.my.php b/Tests/_files/ConcreteTest.my.php deleted file mode 100644 index ea9f8f136b4..00000000000 --- a/Tests/_files/ConcreteTest.my.php +++ /dev/null @@ -1,9 +0,0 @@ -assertEquals($c, $a + $b); - } - - public static function providerMethod() - { - return array( - array(0, 0, 0), - array(0, 1, 1), - array(1, 1, 3), - array(1, 0, 1) - ); - } -} diff --git a/Tests/_files/DependencyFailureTest.php b/Tests/_files/DependencyFailureTest.php deleted file mode 100644 index d83aecd8267..00000000000 --- a/Tests/_files/DependencyFailureTest.php +++ /dev/null @@ -1,22 +0,0 @@ -fail(); - } - - /** - * @depends testOne - */ - public function testTwo() - { - } - - /** - * @depends testTwo - */ - public function testThree() - { - } -} diff --git a/Tests/_files/DependencySuccessTest.php b/Tests/_files/DependencySuccessTest.php deleted file mode 100644 index 0e4b5ddeb2c..00000000000 --- a/Tests/_files/DependencySuccessTest.php +++ /dev/null @@ -1,21 +0,0 @@ -addTestSuite('DependencySuccessTest'); - $suite->addTestSuite('DependencyFailureTest'); - - return $suite; - } -} diff --git a/Tests/_files/DoubleTestCase.php b/Tests/_files/DoubleTestCase.php deleted file mode 100644 index ba601a4a28f..00000000000 --- a/Tests/_files/DoubleTestCase.php +++ /dev/null @@ -1,25 +0,0 @@ -testCase = $testCase; - } - - public function count() - { - return 2; - } - - public function run(PHPUnit_Framework_TestResult $result = NULL) - { - $result->startTest($this); - - $this->testCase->runBare(); - $this->testCase->runBare(); - - $result->endTest($this, 0); - } -} diff --git a/Tests/_files/DummyException.php b/Tests/_files/DummyException.php deleted file mode 100644 index 29a69b997dd..00000000000 --- a/Tests/_files/DummyException.php +++ /dev/null @@ -1,5 +0,0 @@ -setUp = TRUE; - } - - protected function assertPreConditions() - { - $this->assertPreConditions = TRUE; - } - - public function testSomething() - { - $this->testSomething = TRUE; - } - - protected function assertPostConditions() - { - $this->assertPostConditions = TRUE; - throw new Exception; - } - - protected function tearDown() - { - $this->tearDown = TRUE; - } -} diff --git a/Tests/_files/ExceptionInAssertPreConditionsTest.php b/Tests/_files/ExceptionInAssertPreConditionsTest.php deleted file mode 100644 index 01f571affdf..00000000000 --- a/Tests/_files/ExceptionInAssertPreConditionsTest.php +++ /dev/null @@ -1,35 +0,0 @@ -setUp = TRUE; - } - - protected function assertPreConditions() - { - $this->assertPreConditions = TRUE; - throw new Exception; - } - - public function testSomething() - { - $this->testSomething = TRUE; - } - - protected function assertPostConditions() - { - $this->assertPostConditions = TRUE; - } - - protected function tearDown() - { - $this->tearDown = TRUE; - } -} diff --git a/Tests/_files/ExceptionInSetUpTest.php b/Tests/_files/ExceptionInSetUpTest.php deleted file mode 100644 index e0861cd232c..00000000000 --- a/Tests/_files/ExceptionInSetUpTest.php +++ /dev/null @@ -1,35 +0,0 @@ -setUp = TRUE; - throw new Exception; - } - - protected function assertPreConditions() - { - $this->assertPreConditions = TRUE; - } - - public function testSomething() - { - $this->testSomething = TRUE; - } - - protected function assertPostConditions() - { - $this->assertPostConditions = TRUE; - } - - protected function tearDown() - { - $this->tearDown = TRUE; - } -} diff --git a/Tests/_files/ExceptionInTearDownTest.php b/Tests/_files/ExceptionInTearDownTest.php deleted file mode 100644 index 3688dfca3a3..00000000000 --- a/Tests/_files/ExceptionInTearDownTest.php +++ /dev/null @@ -1,35 +0,0 @@ -setUp = TRUE; - } - - protected function assertPreConditions() - { - $this->assertPreConditions = TRUE; - } - - public function testSomething() - { - $this->testSomething = TRUE; - } - - protected function assertPostConditions() - { - $this->assertPostConditions = TRUE; - } - - protected function tearDown() - { - $this->tearDown = TRUE; - throw new Exception; - } -} diff --git a/Tests/_files/ExceptionInTest.php b/Tests/_files/ExceptionInTest.php deleted file mode 100644 index 2b1b66cadf7..00000000000 --- a/Tests/_files/ExceptionInTest.php +++ /dev/null @@ -1,35 +0,0 @@ -setUp = TRUE; - } - - protected function assertPreConditions() - { - $this->assertPreConditions = TRUE; - } - - public function testSomething() - { - $this->testSomething = TRUE; - throw new Exception; - } - - protected function assertPostConditions() - { - $this->assertPostConditions = TRUE; - } - - protected function tearDown() - { - $this->tearDown = TRUE; - } -} diff --git a/Tests/_files/ExceptionNamespaceTest.php b/Tests/_files/ExceptionNamespaceTest.php deleted file mode 100644 index 9644aae6d22..00000000000 --- a/Tests/_files/ExceptionNamespaceTest.php +++ /dev/null @@ -1,38 +0,0 @@ -assertEquals(array(1), array(2), 'message'); - } catch (PHPUnit_Framework_ExpectationFailedException $e) { - $message = $e->getMessage() . "\n" . $e->getComparisonFailure()->getDiff(); - throw new ExceptionStackTestException("Child exception\n$message", 101, $e); - } - } - - public function testNestedExceptions() - { - $exceptionThree = new Exception('Three'); - $exceptionTwo = new InvalidArgumentException('Two', 0, $exceptionThree); - $exceptionOne = new Exception('One', 0, $exceptionTwo); - throw $exceptionOne; - } -} diff --git a/Tests/_files/ExceptionTest.php b/Tests/_files/ExceptionTest.php deleted file mode 100644 index 55c18e436d7..00000000000 --- a/Tests/_files/ExceptionTest.php +++ /dev/null @@ -1,97 +0,0 @@ -fail(); - } -} diff --git a/Tests/_files/FailureTest.php b/Tests/_files/FailureTest.php deleted file mode 100644 index 89a5843a64c..00000000000 --- a/Tests/_files/FailureTest.php +++ /dev/null @@ -1,76 +0,0 @@ -assertEquals(array(1), array(2), 'message'); - } - - public function testAssertIntegerEqualsInteger() - { - $this->assertEquals(1, 2, 'message'); - } - - public function testAssertObjectEqualsObject() - { - $a = new StdClass; - $a->foo = 'bar'; - - $b = new StdClass; - $b->bar = 'foo'; - - $this->assertEquals($a, $b, 'message'); - } - - public function testAssertNullEqualsString() - { - $this->assertEquals(NULL, 'bar', 'message'); - } - - public function testAssertStringEqualsString() - { - $this->assertEquals('foo', 'bar', 'message'); - } - - public function testAssertTextEqualsText() - { - $this->assertEquals("foo\nbar\n", "foo\nbaz\n", 'message'); - } - - public function testAssertStringMatchesFormat() - { - $this->assertStringMatchesFormat('*%s*', '**', 'message'); - } - - public function testAssertNumericEqualsNumeric() - { - $this->assertEquals(1, 2, 'message'); - } - - public function testAssertTextSameText() - { - $this->assertSame('foo', 'bar', 'message'); - } - - public function testAssertObjectSameObject() - { - $this->assertSame(new StdClass, new StdClass, 'message'); - } - - public function testAssertObjectSameNull() - { - $this->assertSame(new StdClass, NULL, 'message'); - } - - public function testAssertFloatSameFloat() - { - $this->assertSame(1.0, 1.5, 'message'); - } - - // Note that due to the implementation of this assertion it counts as 2 asserts - public function testAssertStringMatchesFormatFile() - { - $this->assertStringMatchesFormatFile(__DIR__ . '/expectedFileFormat.txt', '...BAR...'); - } - -} diff --git a/Tests/_files/FatalTest.php b/Tests/_files/FatalTest.php deleted file mode 100644 index 85bdb19f27a..00000000000 --- a/Tests/_files/FatalTest.php +++ /dev/null @@ -1,14 +0,0 @@ -markTestIncomplete('Test incomplete'); - } -} diff --git a/Tests/_files/InheritedTestCase.php b/Tests/_files/InheritedTestCase.php deleted file mode 100644 index 1a15eb63812..00000000000 --- a/Tests/_files/InheritedTestCase.php +++ /dev/null @@ -1,9 +0,0 @@ -assertEquals('application/x-test', ini_get('default_mimetype')); - } -} diff --git a/Tests/_files/JsonData/simpleObject2.js b/Tests/_files/JsonData/simpleObject2.js deleted file mode 100644 index 27085be255a..00000000000 --- a/Tests/_files/JsonData/simpleObject2.js +++ /dev/null @@ -1 +0,0 @@ -{"Mascott":"Tux"} \ No newline at end of file diff --git a/Tests/_files/MockRunner.php b/Tests/_files/MockRunner.php deleted file mode 100644 index b3bc0cc4882..00000000000 --- a/Tests/_files/MockRunner.php +++ /dev/null @@ -1,7 +0,0 @@ -assertEquals('foo', $a); - $this->assertEquals('bar', $b); - } -} diff --git a/Tests/_files/NoArgTestCaseTest.php b/Tests/_files/NoArgTestCaseTest.php deleted file mode 100644 index 5867ba3c958..00000000000 --- a/Tests/_files/NoArgTestCaseTest.php +++ /dev/null @@ -1,7 +0,0 @@ -expectOutputString('foo'); - print 'foo'; - } - - public function testExpectOutputStringFooActualBar() - { - $this->expectOutputString('foo'); - print 'bar'; - } - - public function testExpectOutputRegexFooActualFoo() - { - $this->expectOutputRegex('/foo/'); - print 'foo'; - } - - public function testExpectOutputRegexFooActualBar() - { - $this->expectOutputRegex('/foo/'); - print 'bar'; - } -} diff --git a/Tests/_files/OverrideTestCase.php b/Tests/_files/OverrideTestCase.php deleted file mode 100644 index 63ca294dd7d..00000000000 --- a/Tests/_files/OverrideTestCase.php +++ /dev/null @@ -1,9 +0,0 @@ -a = $a; - $this->b = $b; - $this->c = $c; - } -} diff --git a/Tests/_files/SelectorAssertionsFixture.html b/Tests/_files/SelectorAssertionsFixture.html deleted file mode 100644 index 41256dab825..00000000000 --- a/Tests/_files/SelectorAssertionsFixture.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - Login - - - - -
    -
  • Test LI 1
  • -
  • Test LI 2
  • -
  • Test LI 3
  • -
-
    -
  • Test LI 4
  • -
-
-
- My Subchild - My Child -
- - Test Id Text -
-
- My Children -
1
-
2
-
3
-
4
-
- - Test Class Text - - Login Logo - -
- My test tag content -
more text
-
-
test
- - diff --git a/Tests/_files/Singleton.php b/Tests/_files/Singleton.php deleted file mode 100644 index 77240867c06..00000000000 --- a/Tests/_files/Singleton.php +++ /dev/null @@ -1,22 +0,0 @@ -assertEquals(0, count($stack)); - - array_push($stack, 'foo'); - $this->assertEquals('foo', $stack[count($stack)-1]); - $this->assertEquals(1, count($stack)); - - return $stack; - } - - /** - * @depends testPush - */ - public function testPop(array $stack) - { - $this->assertEquals('foo', array_pop($stack)); - $this->assertEquals(0, count($stack)); - } -} diff --git a/Tests/_files/Struct.php b/Tests/_files/Struct.php deleted file mode 100644 index 12977a996af..00000000000 --- a/Tests/_files/Struct.php +++ /dev/null @@ -1,10 +0,0 @@ -var = $var; - } -} diff --git a/Tests/_files/Success.php b/Tests/_files/Success.php deleted file mode 100644 index 6d3dd61888b..00000000000 --- a/Tests/_files/Success.php +++ /dev/null @@ -1,7 +0,0 @@ -assertTrue(TRUE); - } - - public function testTwo() - { - print __METHOD__ . "\n"; - $this->assertTrue(FALSE); - } - - protected function assertPostConditions() - { - print __METHOD__ . "\n"; - } - - protected function tearDown() - { - print __METHOD__ . "\n"; - } - - public static function tearDownAfterClass() - { - print __METHOD__ . "\n"; - } - - protected function onNotSuccessfulTest(Exception $e) - { - print __METHOD__ . "\n"; - throw $e; - } -} -?> diff --git a/Tests/_files/TestIterator.php b/Tests/_files/TestIterator.php deleted file mode 100644 index c834efbb287..00000000000 --- a/Tests/_files/TestIterator.php +++ /dev/null @@ -1,36 +0,0 @@ -array = $array; - } - - public function rewind() - { - $this->position = 0; - } - - public function valid() - { - return $this->position < count($this->array); - } - - public function key() - { - return $this->position; - } - - public function current() - { - return $this->array[$this->position]; - } - - public function next() - { - $this->position++; - } -} diff --git a/Tests/_files/ThrowExceptionTestCase.php b/Tests/_files/ThrowExceptionTestCase.php deleted file mode 100644 index 0f8af55d263..00000000000 --- a/Tests/_files/ThrowExceptionTestCase.php +++ /dev/null @@ -1,8 +0,0 @@ -wasRun = TRUE; - } -} diff --git a/Tests/_files/configuration.custom-printer.xml b/Tests/_files/configuration.custom-printer.xml deleted file mode 100644 index cbad280c190..00000000000 --- a/Tests/_files/configuration.custom-printer.xml +++ /dev/null @@ -1,2 +0,0 @@ - - \ No newline at end of file diff --git a/Tests/_files/configuration.xml b/Tests/_files/configuration.xml deleted file mode 100644 index 46bc45161d7..00000000000 --- a/Tests/_files/configuration.xml +++ /dev/null @@ -1,115 +0,0 @@ - - - - - - /path/to/files - /path/to/MyTest.php - - - - - - name - - - name - - - - - - /path/to/files - /path/to/file - - /path/to/files - /path/to/file - - - - /path/to/files - /path/to/file - - /path/to/files - /path/to/file - - - - - - - - - - Sebastian - - - 22 - April - 19.78 - - - MyTestFile.php - MyRelativePath - - - - 42 - - - - - - - - - - - - - - - . - /path/to/lib - - - - - - - - - - - - - - - - - - diff --git a/Tests/_files/configuration_xinclude.xml b/Tests/_files/configuration_xinclude.xml deleted file mode 100644 index 50faa81546d..00000000000 --- a/Tests/_files/configuration_xinclude.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - . - /path/to/lib - - - - - - - - - - - - - - - - diff --git a/build.xml b/build.xml index 5cb31de85ce..5aada315374 100644 --- a/build.xml +++ b/build.xml @@ -1,220 +1,439 @@ + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/PHPCS/Sniffs/ControlStructures/ControlSignatureSniff.php b/build/PHPCS/Sniffs/ControlStructures/ControlSignatureSniff.php deleted file mode 100644 index 31a2c878f47..00000000000 --- a/build/PHPCS/Sniffs/ControlStructures/ControlSignatureSniff.php +++ /dev/null @@ -1,23 +0,0 @@ -getTokens(); - - if ($tokens[($stackPtr - 1)]['code'] !== T_WHITESPACE || - $tokens[($stackPtr + 1)]['code'] !== T_WHITESPACE) { - - $phpcsFile->addError( - 'Concatenation operator must be surrounded by whitespace', - $stackPtr - ); - } - } -} diff --git a/build/PHPCS/ruleset.xml b/build/PHPCS/ruleset.xml deleted file mode 100644 index 402f2140b59..00000000000 --- a/build/PHPCS/ruleset.xml +++ /dev/null @@ -1,35 +0,0 @@ - - - Sebastian Bergmann's coding standard - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/config/php-scoper.php b/build/config/php-scoper.php new file mode 100644 index 00000000000..979bdaccd72 --- /dev/null +++ b/build/config/php-scoper.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +return [ + 'prefix' => 'PHPUnitPHAR', + + 'exclude-namespaces' => [ + 'PHPUnit', + ], + + 'expose-constants' => [ + '/^__PHPUNIT_.+$/' + ], +]; diff --git a/build/dependencies/DbUnit-1.2.3.tgz b/build/dependencies/DbUnit-1.2.3.tgz deleted file mode 100644 index 85241bc3346..00000000000 Binary files a/build/dependencies/DbUnit-1.2.3.tgz and /dev/null differ diff --git a/build/dependencies/File_Iterator-1.3.3.tgz b/build/dependencies/File_Iterator-1.3.3.tgz deleted file mode 100644 index 5146caf7833..00000000000 Binary files a/build/dependencies/File_Iterator-1.3.3.tgz and /dev/null differ diff --git a/build/dependencies/PHPUnit_MockObject-1.2.3.tgz b/build/dependencies/PHPUnit_MockObject-1.2.3.tgz deleted file mode 100644 index 4ed09b153c9..00000000000 Binary files a/build/dependencies/PHPUnit_MockObject-1.2.3.tgz and /dev/null differ diff --git a/build/dependencies/PHPUnit_Selenium-1.2.12.tgz b/build/dependencies/PHPUnit_Selenium-1.2.12.tgz deleted file mode 100644 index 3ee899af212..00000000000 Binary files a/build/dependencies/PHPUnit_Selenium-1.2.12.tgz and /dev/null differ diff --git a/build/dependencies/PHP_CodeCoverage-1.2.9.tgz b/build/dependencies/PHP_CodeCoverage-1.2.9.tgz deleted file mode 100644 index 01d8114e2fa..00000000000 Binary files a/build/dependencies/PHP_CodeCoverage-1.2.9.tgz and /dev/null differ diff --git a/build/dependencies/PHP_Invoker-1.1.2.tgz b/build/dependencies/PHP_Invoker-1.1.2.tgz deleted file mode 100644 index 56f6866a487..00000000000 Binary files a/build/dependencies/PHP_Invoker-1.1.2.tgz and /dev/null differ diff --git a/build/dependencies/PHP_Timer-1.0.4.tgz b/build/dependencies/PHP_Timer-1.0.4.tgz deleted file mode 100644 index 83db9c0b0ed..00000000000 Binary files a/build/dependencies/PHP_Timer-1.0.4.tgz and /dev/null differ diff --git a/build/dependencies/PHP_TokenStream-1.1.5.tgz b/build/dependencies/PHP_TokenStream-1.1.5.tgz deleted file mode 100644 index f12f6087217..00000000000 Binary files a/build/dependencies/PHP_TokenStream-1.1.5.tgz and /dev/null differ diff --git a/build/dependencies/Text_Template-1.1.4.tgz b/build/dependencies/Text_Template-1.1.4.tgz deleted file mode 100644 index 2ce0ffeaa69..00000000000 Binary files a/build/dependencies/Text_Template-1.1.4.tgz and /dev/null differ diff --git a/build/dependencies/Yaml-2.2.0.tgz b/build/dependencies/Yaml-2.2.0.tgz deleted file mode 100644 index 8aecbcacb08..00000000000 Binary files a/build/dependencies/Yaml-2.2.0.tgz and /dev/null differ diff --git a/build/phar-autoload.php.in b/build/phar-autoload.php.in deleted file mode 100644 index e9b53d0cf03..00000000000 --- a/build/phar-autoload.php.in +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env php - - - - Sebastian Bergmann's ruleset - - - - - - - - - - - - - - - - - - - diff --git a/build/scripts/check-scoped-phar.php b/build/scripts/check-scoped-phar.php new file mode 100755 index 00000000000..c10171f371e --- /dev/null +++ b/build/scripts/check-scoped-phar.php @@ -0,0 +1,63 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +if (!isset($argv[1]) || !\file_exists($argv[1])) { + \fwrite( + \STDERR, + \sprintf( + '%s /path/to/phpunit-*.phar' . \PHP_EOL, + $argv[0] + ) + ); + + exit(1); +} + +if (!str_contains_between(\file_get_contents($argv[1]), 'PHPUnitPHAR', '$classes = [', '];') && + !str_contains_between(\file_get_contents($argv[1]), 'phpunitphar', '$classes = [', '];')) { + \fwrite(\STDERR, 'PHAR is not scoped' . \PHP_EOL); + + exit(1); +} + +\fwrite(\STDOUT, 'PHAR is scoped' . \PHP_EOL); + +/** + * @param non-empty-string $haystack + * @param non-empty-string $needle + * @param non-empty-string $start + * @param non-empty-string $end + */ +function str_contains_between(string $haystack, string $needle, string $start, string $end): bool +{ + $startLen = \strlen($start); + $needleLen = \strlen($needle); + $offset = 0; + + while (($sPos = \strpos($haystack, $start, $offset)) !== false) { + $afterStart = $sPos + $startLen; + $ePos = \strpos($haystack, $end, $afterStart); + + if ($ePos === false) { + break; + } + + $nPos = \strpos($haystack, $needle, $afterStart); + + if ($nPos !== false && $nPos + $needleLen <= $ePos) { + return true; + } + + $offset = $sPos + 1; + } + + return false; +} diff --git a/build/scripts/extract-release-notes.php b/build/scripts/extract-release-notes.php new file mode 100755 index 00000000000..050766ede1d --- /dev/null +++ b/build/scripts/extract-release-notes.php @@ -0,0 +1,70 @@ +#!/usr/bin/env php +' . PHP_EOL; + + exit(1); +} + +$version = $argv[1]; +$versionSeries = explode('.', $version)[0] . '.' . explode('.', $version)[1]; + +$file = __DIR__ . '/../../ChangeLog-' . $versionSeries . '.md'; + +if (!is_file($file) || !is_readable($file)) { + print $file . ' cannot be read' . PHP_EOL; + + exit(1); +} + +$buffer = ''; +$append = false; + +foreach (file($file) as $line) { + if (str_starts_with($line, '## [' . $version . ']')) { + $append = true; + + continue; + } + + if ($append && (str_starts_with($line, '## ') || str_starts_with($line, '['))) { + break; + } + + if ($append) { + $buffer .= $line; + } +} + +$buffer = trim($buffer); + +if ($buffer === '') { + print 'Unable to extract release notes' . PHP_EOL; + + exit(1); +} + +print $buffer . PHP_EOL; + +$template = <<<'EOT' + +--- + +Learn how to install or update PHPUnit {{versionSeries}} in the [documentation](https://docs.phpunit.de/en/{{versionSeries}}/installation.html). + +#### Keep up to date with PHPUnit: + +* You can follow [@phpunit@phpc.social](https://phpc.social/@phpunit) to stay up to date with PHPUnit's development. +* You can subscribe to the [PHPUnit Updates](https://phpunit.de/newsletter) newsletter to receive updates about and tips for PHPUnit. + +EOT; + +print str_replace( + [ + '{{versionSeries}}', + ], + [ + $versionSeries, + ], + $template, +); diff --git a/build/scripts/generate-global-assert-wrappers.php b/build/scripts/generate-global-assert-wrappers.php new file mode 100755 index 00000000000..d53bac1c421 --- /dev/null +++ b/build/scripts/generate-global-assert-wrappers.php @@ -0,0 +1,212 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use ArrayAccess; +use Countable; +use DOMDocument; +use DOMElement; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; +use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls as ConsecutiveCallsStub; +use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; +use PHPUnit\Framework\MockObject\Stub\ReturnArgument as ReturnArgumentStub; +use PHPUnit\Framework\MockObject\Stub\ReturnCallback as ReturnCallbackStub; +use PHPUnit\Framework\MockObject\Stub\ReturnSelf as ReturnSelfStub; +use PHPUnit\Framework\MockObject\Stub\ReturnStub; +use PHPUnit\Framework\MockObject\Stub\ReturnValueMap as ReturnValueMapStub; +use PHPUnit\Util\Xml\XmlException; +'; + +$usedClasses = []; + +$class = new ReflectionClass(Assert::class); + +$constraintMethods = ''; + +foreach ($class->getMethods() as $method) { + $returnType = $method->getReturnType(); + + assert($returnType instanceof ReflectionNamedType || $returnType instanceof ReflectionUnionType); + + if ($returnType instanceof ReflectionNamedType && $returnType->isBuiltin()) { + continue; + } + + $returnType = new ReflectionClass($returnType->getName()); + + if (!$returnType->isSubclassOf(Constraint::class)) { + continue; + } + + $usedClasses[] = $returnType->getName(); + + // skip, so we can later on append a signature including precise analysis types + if ($method->getName() === 'callback') { + continue; + } + + $constraintMethods .= \sprintf( + "if (!function_exists('PHPUnit\Framework\\" . $method->getName() . "')) {\n%s\n{\n return Assert::%s(...\\func_get_args());\n}\n}\n\n", + \str_replace('final public static ', '', \trim($lines[$method->getStartLine() - 1])), + $method->getName() + ); +} + +$usedClasses = \array_unique($usedClasses); +\sort($usedClasses); + +foreach ($usedClasses as $usedClass) { + $buffer .= \sprintf( + "use %s;\n", + $usedClass + ); +} + +$buffer .= "\n"; + +foreach ($class->getMethods() as $method) { + if (\strpos($method->getName(), 'assert') !== 0) { + continue; + } + + $docComment = \str_replace( + ['*/', ' *'], + ["*\n * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit\n * @see Assert::" . $method->getName() . "\n */", ' *'], + (string) $method->getDocComment() + ); + + $signature = \str_replace('final public static ', '', \trim($lines[$method->getStartLine() - 1])); + $body = "{\n Assert::" . $method->getName() . "(...\\func_get_args());\n}"; + + $buffer .= "if (!function_exists('PHPUnit\Framework\\" . $method->getName() . "')) {\n"; + $buffer .= "$docComment\n$signature\n$body\n"; + $buffer .= "}\n\n"; +} + +$buffer .= $constraintMethods; + +$buffer .= <<<'EOT' +if (!function_exists('PHPUnit\Framework\callback')) { + /** + * @template CallbackInput of mixed + * + * @param callable(CallbackInput $callback): bool $callback + * + * @return Callback + */ + function callback(callable $callback): Callback + { + return Assert::callback($callback); + } +} + +if (!function_exists('PHPUnit\Framework\any')) { + /** + * Returns a matcher that matches when the method is executed + * zero or more times. + */ + function any(): AnyInvokedCountMatcher + { + return new AnyInvokedCountMatcher; + } +} + +if (!function_exists('PHPUnit\Framework\never')) { + /** + * Returns a matcher that matches when the method is never executed. + */ + function never(): InvokedCountMatcher + { + return new InvokedCountMatcher(0); + } +} + +if (!function_exists('PHPUnit\Framework\atLeast')) { + /** + * Returns a matcher that matches when the method is executed + * at least N times. + */ + function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher + { + return new InvokedAtLeastCountMatcher( + $requiredInvocations + ); + } +} + +if (!function_exists('PHPUnit\Framework\atLeastOnce')) { + /** + * Returns a matcher that matches when the method is executed at least once. + */ + function atLeastOnce(): InvokedAtLeastOnceMatcher + { + return new InvokedAtLeastOnceMatcher; + } +} + +if (!function_exists('PHPUnit\Framework\once')) { + /** + * Returns a matcher that matches when the method is executed exactly once. + */ + function once(): InvokedCountMatcher + { + return new InvokedCountMatcher(1); + } +} + +if (!function_exists('PHPUnit\Framework\exactly')) { + /** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */ + function exactly(int $count): InvokedCountMatcher + { + return new InvokedCountMatcher($count); + } +} + +if (!function_exists('PHPUnit\Framework\atMost')) { + /** + * Returns a matcher that matches when the method is executed + * at most N times. + */ + function atMost(int $allowedInvocations): InvokedAtMostCountMatcher + { + return new InvokedAtMostCountMatcher($allowedInvocations); + } +} + +if (!function_exists('PHPUnit\Framework\throwException')) { + function throwException(\Throwable $exception): ExceptionStub + { + return new ExceptionStub($exception); + } +} + +EOT; + +\file_put_contents(__DIR__ . '/../../src/Framework/Assert/Functions.php', $buffer); diff --git a/build/scripts/phar-manifest.php b/build/scripts/phar-manifest.php new file mode 100755 index 00000000000..97a0afe9489 --- /dev/null +++ b/build/scripts/phar-manifest.php @@ -0,0 +1,173 @@ +#!/usr/bin/env php +openMemory(); + $writer->setIndent(true); + $writer->startDocument(); + + $writer->startElement('bom'); + $writer->writeAttribute('xmlns', 'http://cyclonedx.org/schema/bom/1.4'); + + $writer->startElement('components'); + + writeComponent( + $writer, + $package['group'], + $package['name'], + $version, + $package['description'], + $package['license'] + ); + + foreach ($dependencies as $dependency) { + [$group, $name] = explode('/', $dependency['name']); + + writeComponent( + $writer, + $group, + $name, + versionWithReference( + $dependency['version'], + $dependency['source']['reference'] + ), + $dependency['description'], + $dependency['license'] + ); + } + + $writer->endElement(); + $writer->endElement(); + $writer->endDocument(); + + file_put_contents($outputFilename, $writer->outputMemory()); +} + +function package(): array +{ + $data = json_decode( + file_get_contents( + __DIR__ . '/../../composer.json' + ), + true + ); + + [$group, $name] = explode('/', $data['name']); + + return [ + 'group' => $group, + 'name' => $name, + 'description' => $data['description'], + 'license' => [$data['license']], + ]; +} + +function version(): string +{ + $tag = @exec('git describe --tags 2>&1'); + + if (strpos($tag, '-') === false && strpos($tag, 'No names found') === false) { + return $tag; + } + + $branch = @exec('git rev-parse --abbrev-ref HEAD'); + $hash = @exec('git log -1 --format="%H"'); + + return $branch . '@' . $hash; +} + +function dependencies(): array +{ + return json_decode( + file_get_contents( + __DIR__ . '/../../composer.lock' + ), + true + )['packages']; +} + +function versionWithReference(string $version, string $reference): string +{ + if (!preg_match('/^[v= ]*(([0-9]+)(\\.([0-9]+)(\\.([0-9]+)(-([0-9]+))?(-?([a-zA-Z-+][a-zA-Z0-9.\\-:]*)?)?)?)?)$/', $version)) { + $version .= '@' . $reference; + } + + return $version; +} + +function writeComponent(XMLWriter $writer, string $group, string $name, string $version, string $description, array $licenses): void +{ + $writer->startElement('component'); + $writer->writeAttribute('type', 'library'); + + $writer->writeElement('group', $group); + $writer->writeElement('name', $name); + $writer->writeElement('version', $version); + $writer->writeElement('description', $description); + + $writer->startElement('licenses'); + + foreach ($licenses as $license) { + $writer->startElement('license'); + $writer->writeElement('id', $license); + $writer->endElement(); + } + + $writer->endElement(); + + $writer->writeElement( + 'purl', + sprintf( + 'pkg:composer/%s/%s@%s', + $group, + $name, + $version + ) + ); + + $writer->endElement(); +} diff --git a/build/scripts/phar-set-timestamps/composer.json b/build/scripts/phar-set-timestamps/composer.json new file mode 100644 index 00000000000..4369496d0e6 --- /dev/null +++ b/build/scripts/phar-set-timestamps/composer.json @@ -0,0 +1,8 @@ +{ + "require": { + "seld/phar-utils": "^1.2" + }, + "config": { + "optimize-autoloader": true + } +} diff --git a/build/scripts/phar-set-timestamps/composer.lock b/build/scripts/phar-set-timestamps/composer.lock new file mode 100644 index 00000000000..e3c10072c6e --- /dev/null +++ b/build/scripts/phar-set-timestamps/composer.lock @@ -0,0 +1,67 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "a2828bc624be51258ae32a2f2dbd5696", + "packages": [ + { + "name": "seld/phar-utils", + "version": "1.2.1", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "time": "2022-08-31T10:31:18+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": [], + "platform-dev": [], + "plugin-api-version": "2.6.0" +} diff --git a/build/scripts/phar-set-timestamps/run.php b/build/scripts/phar-set-timestamps/run.php new file mode 100755 index 00000000000..d845e2b9f3b --- /dev/null +++ b/build/scripts/phar-set-timestamps/run.php @@ -0,0 +1,54 @@ +#!/usr/bin/env php +&1'); + + if (is_string($tag) && strpos($tag, 'fatal') === false) { + $tmp = @shell_exec('git log -1 --format=%at ' . trim($tag) . ' 2>&1'); + + if (is_string($tag) && is_numeric(trim($tmp))) { + $epoch = (int) trim($tmp); + + printf( + 'Setting timestamp of files in PHAR to %d (based on when tag %s was created)' . PHP_EOL, + $epoch, + trim($tag) + ); + } + + unset($tmp); + } + + unset($tag); +} + +if (!isset($epoch)) { + $epoch = time(); + + printf( + 'Setting timestamp of files in PHAR to %d (based on current time)' . PHP_EOL, + $epoch + ); +} + +$timestamp = new DateTime; +$timestamp->setTimestamp($epoch); + +$util = new Timestamps($argv[1]); +$util->updateTimestamps($timestamp); +$util->save($argv[1], Phar::SHA512); diff --git a/build/scripts/phar-set-timestamps/vendor/autoload.php b/build/scripts/phar-set-timestamps/vendor/autoload.php new file mode 100644 index 00000000000..bb1037c7c3b --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/autoload.php @@ -0,0 +1,25 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/composer/InstalledVersions.php b/build/scripts/phar-set-timestamps/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000000..51e734a774b --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/InstalledVersions.php @@ -0,0 +1,359 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + + if (self::$canGetVendors) { + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; + if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { + self::$installed = $installed[count($installed) - 1]; + } + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/composer/LICENSE b/build/scripts/phar-set-timestamps/vendor/composer/LICENSE new file mode 100644 index 00000000000..f27399a042d --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/build/scripts/phar-set-timestamps/vendor/composer/autoload_classmap.php b/build/scripts/phar-set-timestamps/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000000..e6a22096ae5 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/autoload_classmap.php @@ -0,0 +1,12 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Seld\\PharUtils\\Linter' => $vendorDir . '/seld/phar-utils/src/Linter.php', + 'Seld\\PharUtils\\Timestamps' => $vendorDir . '/seld/phar-utils/src/Timestamps.php', +); diff --git a/build/scripts/phar-set-timestamps/vendor/composer/autoload_namespaces.php b/build/scripts/phar-set-timestamps/vendor/composer/autoload_namespaces.php new file mode 100644 index 00000000000..15a2ff3ad6d --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/seld/phar-utils/src'), +); diff --git a/build/scripts/phar-set-timestamps/vendor/composer/autoload_real.php b/build/scripts/phar-set-timestamps/vendor/composer/autoload_real.php new file mode 100644 index 00000000000..69cfbf7e33c --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/autoload_real.php @@ -0,0 +1,38 @@ +register(true); + + return $loader; + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/composer/autoload_static.php b/build/scripts/phar-set-timestamps/vendor/composer/autoload_static.php new file mode 100644 index 00000000000..201af17c152 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/autoload_static.php @@ -0,0 +1,38 @@ + + array ( + 'Seld\\PharUtils\\' => 15, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'Seld\\PharUtils\\' => + array ( + 0 => __DIR__ . '/..' . '/seld/phar-utils/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Seld\\PharUtils\\Linter' => __DIR__ . '/..' . '/seld/phar-utils/src/Linter.php', + 'Seld\\PharUtils\\Timestamps' => __DIR__ . '/..' . '/seld/phar-utils/src/Timestamps.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInit386a05f6676643b8b2eb49288e20d079::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInit386a05f6676643b8b2eb49288e20d079::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInit386a05f6676643b8b2eb49288e20d079::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/composer/installed.json b/build/scripts/phar-set-timestamps/vendor/composer/installed.json new file mode 100644 index 00000000000..44d066d18b1 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/installed.json @@ -0,0 +1,57 @@ +{ + "packages": [ + { + "name": "seld/phar-utils", + "version": "1.2.1", + "version_normalized": "1.2.1.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/phar-utils.git", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/phar-utils/zipball/ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "reference": "ea2f4014f163c1be4c601b9b7bd6af81ba8d701c", + "shasum": "" + }, + "require": { + "php": ">=5.3" + }, + "time": "2022-08-31T10:31:18+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "description": "PHAR file format utilities, for when PHP phars you up", + "keywords": [ + "phar" + ], + "support": { + "issues": "https://github.com/Seldaek/phar-utils/issues", + "source": "https://github.com/Seldaek/phar-utils/tree/1.2.1" + }, + "install-path": "../seld/phar-utils" + } + ], + "dev": true, + "dev-package-names": [] +} diff --git a/build/scripts/phar-set-timestamps/vendor/composer/installed.php b/build/scripts/phar-set-timestamps/vendor/composer/installed.php new file mode 100644 index 00000000000..6f559f8743b --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/installed.php @@ -0,0 +1,32 @@ + array( + 'name' => '__root__', + 'pretty_version' => '8.5.x-dev', + 'version' => '8.5.9999999.9999999-dev', + 'reference' => 'aca96fcd8b6799ead1066524b2b91c5184ece78f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => '8.5.x-dev', + 'version' => '8.5.9999999.9999999-dev', + 'reference' => 'aca96fcd8b6799ead1066524b2b91c5184ece78f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'seld/phar-utils' => array( + 'pretty_version' => '1.2.1', + 'version' => '1.2.1.0', + 'reference' => 'ea2f4014f163c1be4c601b9b7bd6af81ba8d701c', + 'type' => 'library', + 'install_path' => __DIR__ . '/../seld/phar-utils', + 'aliases' => array(), + 'dev_requirement' => false, + ), + ), +); diff --git a/build/scripts/phar-set-timestamps/vendor/composer/platform_check.php b/build/scripts/phar-set-timestamps/vendor/composer/platform_check.php new file mode 100644 index 00000000000..7621d4ff97f --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/composer/platform_check.php @@ -0,0 +1,26 @@ += 50300)) { + $issues[] = 'Your Composer dependencies require a PHP version ">= 5.3.0". You are running ' . PHP_VERSION . '.'; +} + +if ($issues) { + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . implode(PHP_EOL, $issues) . PHP_EOL.PHP_EOL); + } elseif (!headers_sent()) { + echo 'Composer detected issues in your platform:' . PHP_EOL.PHP_EOL . str_replace('You are running '.PHP_VERSION.'.', '', implode(PHP_EOL, $issues)) . PHP_EOL.PHP_EOL; + } + } + trigger_error( + 'Composer detected issues in your platform: ' . implode(' ', $issues), + E_USER_ERROR + ); +} diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/.gitignore b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/.gitignore new file mode 100644 index 00000000000..42cd73d9573 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/.gitignore @@ -0,0 +1 @@ +/vendor/ \ No newline at end of file diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/LICENSE b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/LICENSE new file mode 100644 index 00000000000..c1b62a35fa3 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/README.md b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/README.md new file mode 100644 index 00000000000..27edf743276 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/README.md @@ -0,0 +1,45 @@ +PHAR Utils +========== + +PHAR file format utilities, for when PHP phars you up. + +Installation +------------ + +`composer require seld/phar-utils` + +API +--- + +### `Seld\PharUtils\Timestamps` + +- `__construct($pharFile)` + + > Load a phar file in memory. + +- `updateTimestamps($timestamp = null)` + + > Updates each file's unix timestamps in the PHAR so the PHAR signature + > can be produced in a reproducible manner. + +- `save($path, $signatureAlgo = '')` + + > Saves the updated phar file with an updated signature. + > Algo must be one of `Phar::MD5`, `Phar::SHA1`, `Phar::SHA256` + > or `Phar::SHA512` + +### `Seld\PharUtils\Linter` + +- `Linter::lint($pharFile)` + + > Lints all php files inside a given phar with the current PHP version. + +Requirements +------------ + +PHP 5.3 and above + +License +------- + +PHAR Utils is licensed under the MIT License - see the LICENSE file for details diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.json b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.json new file mode 100644 index 00000000000..8b1f7f2b68a --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.json @@ -0,0 +1,26 @@ +{ + "name": "seld/phar-utils", + "description": "PHAR file format utilities, for when PHP phars you up", + "type": "library", + "keywords": ["phar"], + "license": "MIT", + "require": { + "php": ">=5.3" + }, + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be" + } + ], + "autoload": { + "psr-4": { + "Seld\\PharUtils\\": "src/" + } + }, + "extra": { + "branch-alias": { + "dev-master": "1.x-dev" + } + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.lock b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.lock new file mode 100644 index 00000000000..21e33c7a217 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/composer.lock @@ -0,0 +1,19 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", + "This file is @generated automatically" + ], + "hash": "e5afe72073d9266712c8e1ddc1648513", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=5.3" + }, + "platform-dev": [] +} diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Linter.php b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Linter.php new file mode 100644 index 00000000000..935d04e8411 --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Linter.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Seld\PharUtils; + +class Linter +{ + /** + * Lints all php files inside a given phar with the current PHP version + * + * @param string $path Phar file path + * @param list $excludedPaths Paths which should be skipped by the linter + */ + public static function lint($path, array $excludedPaths = array()) + { + $php = defined('PHP_BINARY') ? PHP_BINARY : 'php'; + + if ($isWindows = defined('PHP_WINDOWS_VERSION_BUILD')) { + $tmpFile = @tempnam(sys_get_temp_dir(), ''); + + if (!$tmpFile || !is_writable($tmpFile)) { + throw new \RuntimeException('Unable to create temp file'); + } + + $php = self::escapeWindowsPath($php); + $tmpFile = self::escapeWindowsPath($tmpFile); + + // PHP 8 encloses the command in double-quotes + if (PHP_VERSION_ID >= 80000) { + $format = '%s -l %s'; + } else { + $format = '"%s -l %s"'; + } + + $command = sprintf($format, $php, $tmpFile); + } else { + $command = "'".$php."' -l"; + } + + $descriptorspec = array( + 0 => array('pipe', 'r'), + 1 => array('pipe', 'w'), + 2 => array('pipe', 'w') + ); + + // path to phar + phar:// + trailing slash + $baseLen = strlen(realpath($path)) + 7 + 1; + foreach (new \RecursiveIteratorIterator(new \Phar($path)) as $file) { + if ($file->isDir()) { + continue; + } + if (substr($file, -4) === '.php') { + $filename = (string) $file; + if (in_array(substr($filename, $baseLen), $excludedPaths, true)) { + continue; + } + if ($isWindows) { + file_put_contents($tmpFile, file_get_contents($filename)); + } + + $process = proc_open($command, $descriptorspec, $pipes); + if (is_resource($process)) { + if (!$isWindows) { + fwrite($pipes[0], file_get_contents($filename)); + } + fclose($pipes[0]); + + $stdout = stream_get_contents($pipes[1]); + fclose($pipes[1]); + $stderr = stream_get_contents($pipes[2]); + fclose($pipes[2]); + + $exitCode = proc_close($process); + + if ($exitCode !== 0) { + if ($isWindows) { + $stderr = str_replace($tmpFile, $filename, $stderr); + } + throw new \UnexpectedValueException('Failed linting '.$file.': '.$stderr); + } + } else { + throw new \RuntimeException('Could not start linter process'); + } + } + } + + if ($isWindows) { + @unlink($tmpFile); + } + } + + /** + * Escapes a Windows file path + * + * @param string $path + * @return string The escaped path + */ + private static function escapeWindowsPath($path) + { + // Quote if path contains spaces or brackets + if (strpbrk($path, " ()") !== false) { + $path = '"'.$path.'"'; + } + + return $path; + } +} diff --git a/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Timestamps.php b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Timestamps.php new file mode 100644 index 00000000000..8077d5b851d --- /dev/null +++ b/build/scripts/phar-set-timestamps/vendor/seld/phar-utils/src/Timestamps.php @@ -0,0 +1,196 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Seld\PharUtils; + +class Timestamps +{ + private $contents; + + /** + * @param string $file path to the phar file to use + */ + public function __construct($file) + { + $this->contents = file_get_contents($file); + } + + /** + * Updates each file's unix timestamps in the PHAR + * + * The PHAR signature can then be produced in a reproducible manner. + * + * @param int|\DateTimeInterface|string $timestamp Date string or DateTime or unix timestamp to use + */ + public function updateTimestamps($timestamp = null) + { + if ($timestamp instanceof \DateTime || $timestamp instanceof \DateTimeInterface) { + $timestamp = $timestamp->getTimestamp(); + } elseif (is_string($timestamp)) { + $timestamp = strtotime($timestamp); + } elseif (!is_int($timestamp)) { + $timestamp = strtotime('1984-12-24T00:00:00Z'); + } + + // detect manifest offset / end of stub + if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) { + throw new \RuntimeException('Could not detect the stub\'s end in the phar'); + } + + // set starting position and skip past manifest length + $pos = $match[0][1] + strlen($match[0][0]); + $stubEnd = $pos + $this->readUint($pos, 4); + $pos += 4; + + $numFiles = $this->readUint($pos, 4); + $pos += 4; + + // skip API version (YOLO) + $pos += 2; + + // skip PHAR flags + $pos += 4; + + $aliasLength = $this->readUint($pos, 4); + $pos += 4 + $aliasLength; + + $metadataLength = $this->readUint($pos, 4); + $pos += 4 + $metadataLength; + + while ($pos < $stubEnd) { + $filenameLength = $this->readUint($pos, 4); + $pos += 4 + $filenameLength; + + // skip filesize + $pos += 4; + + // update timestamp to a fixed value + $timeStampBytes = pack('L', $timestamp); + $this->contents[$pos + 0] = $timeStampBytes[0]; + $this->contents[$pos + 1] = $timeStampBytes[1]; + $this->contents[$pos + 2] = $timeStampBytes[2]; + $this->contents[$pos + 3] = $timeStampBytes[3]; + + // skip timestamp, compressed file size, crc32 checksum and file flags + $pos += 4*4; + + $metadataLength = $this->readUint($pos, 4); + $pos += 4 + $metadataLength; + + $numFiles--; + } + + if ($numFiles !== 0) { + throw new \LogicException('All files were not processed, something must have gone wrong'); + } + } + + /** + * Saves the updated phar file, optionally with an updated signature. + * + * @param string $path + * @param int $signatureAlgo One of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512 + * @return bool + */ + public function save($path, $signatureAlgo) + { + $pos = $this->determineSignatureBegin(); + + $algos = array( + \Phar::MD5 => 'md5', + \Phar::SHA1 => 'sha1', + \Phar::SHA256 => 'sha256', + \Phar::SHA512 => 'sha512', + ); + + if (!isset($algos[$signatureAlgo])) { + throw new \UnexpectedValueException('Invalid hash algorithm given: '.$signatureAlgo.' expected one of Phar::MD5, Phar::SHA1, Phar::SHA256 or Phar::SHA512'); + } + $algo = $algos[$signatureAlgo]; + + // re-sign phar + // signature + $signature = hash($algo, substr($this->contents, 0, $pos), true) + // sig type + . pack('L', $signatureAlgo) + // ohai Greg & Marcus + . 'GBMB'; + + $this->contents = substr($this->contents, 0, $pos) . $signature; + + return file_put_contents($path, $this->contents); + } + + private function readUint($pos, $bytes) + { + $res = unpack('V', substr($this->contents, $pos, $bytes)); + + return $res[1]; + } + + /** + * Determine the beginning of the signature. + * + * @return int + */ + private function determineSignatureBegin() + { + // detect signature position + if (!preg_match('{__HALT_COMPILER\(\);(?: +\?>)?\r?\n}', $this->contents, $match, PREG_OFFSET_CAPTURE)) { + throw new \RuntimeException('Could not detect the stub\'s end in the phar'); + } + + // set starting position and skip past manifest length + $pos = $match[0][1] + strlen($match[0][0]); + $manifestEnd = $pos + 4 + $this->readUint($pos, 4); + + $pos += 4; + $numFiles = $this->readUint($pos, 4); + + $pos += 4; + + // skip API version (YOLO) + $pos += 2; + + // skip PHAR flags + $pos += 4; + + $aliasLength = $this->readUint($pos, 4); + $pos += 4 + $aliasLength; + + $metadataLength = $this->readUint($pos, 4); + $pos += 4 + $metadataLength; + + $compressedSizes = 0; + while (($numFiles > 0) && ($pos < $manifestEnd - 24)) { + $filenameLength = $this->readUint($pos, 4); + $pos += 4 + $filenameLength; + + // skip filesize and timestamp + $pos += 2*4; + + $compressedSizes += $this->readUint($pos, 4); + // skip compressed file size, crc32 checksum and file flags + $pos += 3*4; + + $metadataLength = $this->readUint($pos, 4); + $pos += 4 + $metadataLength; + + $numFiles--; + } + + if ($numFiles !== 0) { + throw new \LogicException('All files were not processed, something must have gone wrong'); + } + + return $manifestEnd + $compressedSizes; + } +} diff --git a/build/scripts/phar-version.php b/build/scripts/phar-version.php new file mode 100755 index 00000000000..948c3b21b09 --- /dev/null +++ b/build/scripts/phar-version.php @@ -0,0 +1,22 @@ +#!/usr/bin/env php +asString(); diff --git a/build/templates/binary-phar-autoload.php.in b/build/templates/binary-phar-autoload.php.in new file mode 100644 index 00000000000..207d6d73f57 --- /dev/null +++ b/build/templates/binary-phar-autoload.php.in @@ -0,0 +1,127 @@ +#!/usr/bin/env php +')) { + fwrite( + STDERR, + sprintf( + 'PHPUnit X.Y.Z by Sebastian Bergmann and contributors.' . PHP_EOL . PHP_EOL . + 'This version of PHPUnit requires PHP >= 8.4.1.' . PHP_EOL . + 'You are using PHP %s (%s).' . PHP_EOL, + PHP_VERSION, + PHP_BINARY + ) + ); + + die(1); +} + +$requiredExtensions = ['ctype', 'dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter']; + +$unavailableExtensions = array_filter( + $requiredExtensions, + static function ($extension) { + return !extension_loaded($extension); + } +); + +if ([] !== $unavailableExtensions) { + fwrite( + STDERR, + sprintf( + 'PHPUnit requires the "%s" extensions, but the "%s" %s not available.' . PHP_EOL, + implode('", "', $requiredExtensions), + implode('", "', $unavailableExtensions), + count($unavailableExtensions) === 1 ? 'extension is' : 'extensions are' + ) + ); + + die(1); +} + +unset($requiredExtensions, $unavailableExtensions); + +if (__FILE__ === realpath($_SERVER['SCRIPT_NAME'])) { + $execute = true; +} else { + $execute = false; +} + +$options = getopt('', array('composer-lock', 'manifest', 'sbom')); + +if (isset($options['composer-lock'])) { + $printComposerLock = true; +} elseif (isset($options['manifest'])) { + $printManifest = true; +} elseif (isset($options['sbom'])) { + $printSbom = true; +} + +unset($options); + +define('__PHPUNIT_PHAR__', str_replace(DIRECTORY_SEPARATOR, '/', __FILE__)); +define('__PHPUNIT_PHAR_ROOT__', 'phar://___PHAR___'); + +Phar::mapPhar('___PHAR___'); + +spl_autoload_register( + function ($class) { + static $classes = null; + + if ($classes === null) { + $classes = [___CLASSLIST___]; + } + + if (isset($classes[$class])) { + require_once 'phar://___PHAR___' . $classes[$class]; + } + }, + ___EXCEPTION___, + ___PREPEND___ +); + +foreach ([___CLASSLIST___] as $file) { + require_once 'phar://___PHAR___' . $file; +} + +require __PHPUNIT_PHAR_ROOT__ . '/phpunit/Framework/Assert/Functions.php'; + +if ($execute) { + if (isset($printComposerLock)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/composer.lock'); + + exit; + } + + if (isset($printManifest)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/manifest.txt'); + + exit; + } + + if (isset($printSbom)) { + print file_get_contents(__PHPUNIT_PHAR_ROOT__ . '/sbom.xml'); + + exit; + } + + unset($execute); + + exit((new PHPUnit\TextUI\Application)->run($_SERVER['argv'])); +} + +__HALT_COMPILER(); diff --git a/build/templates/library-phar-autoload.php.in b/build/templates/library-phar-autoload.php.in new file mode 100644 index 00000000000..8f3fd2b8acb --- /dev/null +++ b/build/templates/library-phar-autoload.php.in @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + diff --git a/build/test-extension/src/MyExtensionBootstrap.php b/build/test-extension/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..99a8457a1eb --- /dev/null +++ b/build/test-extension/src/MyExtensionBootstrap.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + } +} diff --git a/build/travis-ci.xml b/build/travis-ci.xml deleted file mode 100644 index e1a4866482d..00000000000 --- a/build/travis-ci.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - ../Tests/Framework - ../Tests/Framework/MockObject - ../Tests/Extensions - ../Tests/Regression - ../Tests/Runner - ../Tests/TextUI - ../Tests/Util - - - - - - - - - - ../PHPUnit - - ../PHPUnit/Autoload.php - ../PHPUnit/Framework/Assert/Functions.php - - - - - - - - diff --git a/composer.json b/composer.json index e580cd50cd3..ac14d9e8a1e 100644 --- a/composer.json +++ b/composer.json @@ -7,7 +7,7 @@ "xunit", "testing" ], - "homepage": "http://www.phpunit.de/", + "homepage": "https://phpunit.de/", "license": "BSD-3-Clause", "authors": [ { @@ -18,58 +18,102 @@ ], "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", - "irc": "irc://irc.freenode.net/phpunit" + "security": "https://github.com/sebastianbergmann/phpunit/security/policy" }, - "minimum-stability": "dev", + "prefer-stable": true, "require": { - "php": ">=5.4.7", - "phpunit/php-file-iterator": ">=1.3.1", - "phpunit/php-text-template": ">=1.1.1", - "phpunit/php-code-coverage": "1.3.*@dev", - "phpunit/php-timer": ">=1.1.0", - "phpunit/phpunit-mock-objects": "1.3.*@dev", - "symfony/yaml": ">=2.0.0,<2.3.0", - "sebastian/diff": ">=1.0.0", - "sebastian/exporter": ">=1.0.0", - "sebastian/version": ">=1.0.0", + "php": ">=8.4.1", "ext-dom": "*", - "ext-pcre": "*", - "ext-reflection": "*", - "ext-spl": "*" - }, - "require-dev": { - "pear-pear/pear": "1.9.4" - }, - "repositories": [ - { - "type": "pear", - "url": "http://pear.php.net/" - } - ], - "suggest": { - "phpunit/php-invoker": ">=1.2.0", "ext-json": "*", - "ext-simplexml": "*", - "ext-tokenizer": "*" + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.4", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "phpunit/php-code-coverage": "^12.5.1", + "phpunit/php-file-iterator": "^6.0.0", + "phpunit/php-invoker": "^6.0.0", + "phpunit/php-text-template": "^5.0.0", + "phpunit/php-timer": "^8.0.0", + "sebastian/cli-parser": "^4.2.0", + "sebastian/comparator": "^7.1.3", + "sebastian/diff": "^7.0.0", + "sebastian/environment": "^8.0.3", + "sebastian/exporter": "^7.0.2", + "sebastian/global-state": "^8.0.2", + "sebastian/object-enumerator": "^7.0.0", + "sebastian/type": "^6.0.3", + "sebastian/version": "^6.0.0", + "staabm/side-effects-detector": "^1.0.5" }, - "bin": [ - "composer/bin/phpunit" - ], "config": { - "bin-dir": "bin" + "platform": { + "php": "8.4.1" + }, + "classmap-authoritative": true, + "optimize-autoloader": true, + "sort-packages": true }, + "bin": [ + "phpunit" + ], "autoload": { "classmap": [ - "PHPUnit/" + "src/" + ], + "files": [ + "src/Framework/Assert/Functions.php" + ] + }, + "autoload-dev": { + "classmap": [ + "tests/_files" + ], + "files": [ + "tests/_files/deprecation-trigger/trigger_deprecation.php", + "tests/unit/Event/AbstractEventTestCase.php", + "tests/unit/TextUI/AbstractSouceFilterTestCase.php", + "tests/unit/Framework/MockObject/TestDoubleTestCase.php", + "tests/unit/Metadata/Parser/AttributeParserTestCase.php", + "tests/unit/Framework/Assert/assertContainsOnlyArrayTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyBoolTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyCallableTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyFloatTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyInstancesOfTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyIntTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyIterableTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyNullTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyNumericTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyObjectTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyResourceTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyClosedResourceTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyScalarTest.php", + "tests/unit/Framework/Assert/assertContainsOnlyStringTest.php", + "tests/unit/Framework/Assert/assertDirectoryExistsTest.php", + "tests/unit/Framework/Assert/assertFileExistsTest.php", + "tests/unit/Framework/Assert/assertIsNumericTest.php", + "tests/unit/Framework/Assert/assertIsObjectTest.php", + "tests/unit/Framework/Assert/assertIsReadableTest.php", + "tests/unit/Framework/Assert/assertIsResourceTest.php", + "tests/unit/Framework/Assert/assertIsScalarTest.php", + "tests/unit/Framework/Assert/assertIsStringTest.php", + "tests/unit/Framework/Assert/assertIsWritableTest.php", + "tests/unit/Framework/Assert/assertMatchesRegularExpressionTest.php", + "tests/unit/Framework/Assert/assertNullTest.php", + "tests/unit/Framework/Assert/assertSameSizeTest.php", + "tests/unit/Framework/Assert/assertSameTest.php", + "tests/unit/TextUI/Output/Default/ResultPrinterTest.php", + "tests/_files/CoveredFunction.php", + "tests/_files/Generator.php", + "tests/_files/NamespaceCoveredFunction.php", + "tests/end-to-end/_files/listing-tests-and-groups/ExampleAbstractTestCase.php" ] }, "extra": { "branch-alias": { - "dev-master": "3.8.x-dev" + "dev-main": "13.0-dev" } - }, - "include-path": [ - "", - "../../symfony/yaml/" - ] + } } diff --git a/composer.lock b/composer.lock new file mode 100644 index 00000000000..0c835995294 --- /dev/null +++ b/composer.lock @@ -0,0 +1,1599 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "0767fc66195e9d7c48bd39db47a67e1a", + "packages": [ + { + "name": "myclabs/deep-copy", + "version": "1.13.4", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-08-01T08:46:24+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.7.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.x-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.7.0" + }, + "time": "2025-12-06T11:56:16+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "12.5.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "c467c59a4f6e04b942be422844e7a6352fa01b57" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/c467c59a4f6e04b942be422844e7a6352fa01b57", + "reference": "c467c59a4f6e04b942be422844e7a6352fa01b57", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.7.0", + "php": ">=8.3", + "phpunit/php-file-iterator": "^6.0", + "phpunit/php-text-template": "^5.0", + "sebastian/complexity": "^5.0", + "sebastian/environment": "^8.0.3", + "sebastian/lines-of-code": "^4.0", + "sebastian/version": "^6.0", + "theseer/tokenizer": "^2.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.5.1" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "12.5.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/12.5.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-12-08T07:17:58+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/961bc913d42fe24a257bfff826a5068079ac7782", + "reference": "961bc913d42fe24a257bfff826a5068079ac7782", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:37+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "reference": "12b54e689b07a25a9b41e57736dfab6ec9ae5406", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:58+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/e1367a453f0eda562eedb4f659e13aa900d66c53", + "reference": "e1367a453f0eda562eedb4f659e13aa900d66c53", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:16+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "8.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "reference": "f258ce36aa457f3aa3339f9ed4c81fc66dc8c2cc", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/8.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:59:38+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "4.2.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "reference": "90f41072d220e5c40df6e8635f5dafba2d9d4d04", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/4.2.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/cli-parser", + "type": "tidelift" + } + ], + "time": "2025-09-14T09:36:45+00:00" + }, + { + "name": "sebastian/comparator", + "version": "7.1.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/dc904b4bb3ab070865fa4068cd84f3da8b945148", + "reference": "dc904b4bb3ab070865fa4068cd84f3da8b945148", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/diff": "^7.0", + "sebastian/exporter": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.2" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/7.1.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/comparator", + "type": "tidelift" + } + ], + "time": "2025-08-20T11:27:00+00:00" + }, + { + "name": "sebastian/complexity", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/bad4316aba5303d0221f43f8cee37eb58d384bbb", + "reference": "bad4316aba5303d0221f43f8cee37eb58d384bbb", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:25+00:00" + }, + { + "name": "sebastian/diff", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/7ab1ea946c012266ca32390913653d844ecd085f", + "reference": "7ab1ea946c012266ca32390913653d844ecd085f", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0", + "symfony/process": "^7.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:55:46+00:00" + }, + { + "name": "sebastian/environment", + "version": "8.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "reference": "24a711b5c916efc6d6e62aa65aa2ec98fef77f68", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/8.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-08-12T14:11:56+00:00" + }, + { + "name": "sebastian/exporter", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/016951ae10980765e4e7aee491eb288c64e505b7", + "reference": "016951ae10980765e4e7aee491eb288c64e505b7", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.3", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/exporter", + "type": "tidelift" + } + ], + "time": "2025-09-24T06:16:11+00:00" + }, + { + "name": "sebastian/global-state", + "version": "8.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/ef1377171613d09edd25b7816f05be8313f9115d", + "reference": "ef1377171613d09edd25b7816f05be8313f9115d", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "8.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/8.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/global-state", + "type": "tidelift" + } + ], + "time": "2025-08-29T11:29:25+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "reference": "97ffee3bcfb5805568d6af7f0f893678fc076d2f", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/4.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:28+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "7.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "reference": "1effe8e9b8e068e9ae228e542d5d11b5d16db894", + "shasum": "" + }, + "require": { + "php": ">=8.3", + "sebastian/object-reflector": "^5.0", + "sebastian/recursion-context": "^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/7.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:57:48+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "5.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/4bfa827c969c98be1e527abd576533293c634f6a", + "reference": "4bfa827c969c98be1e527abd576533293c634f6a", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/5.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T04:58:17+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "reference": "0b01998a7d5b1f122911a66bebcb8d46f0c82d8c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/recursion-context", + "type": "tidelift" + } + ], + "time": "2025-08-13T04:44:59+00:00" + }, + { + "name": "sebastian/type", + "version": "6.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/e549163b9760b8f71f191651d22acf32d56d6d4d", + "reference": "e549163b9760b8f71f191651d22acf32d56d6d4d", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "require-dev": { + "phpunit/phpunit": "^12.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/6.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/type", + "type": "tidelift" + } + ], + "time": "2025-08-09T06:57:12+00:00" + }, + { + "name": "sebastian/version", + "version": "6.0.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/3e6ccf7657d4f0a59200564b08cead899313b53c", + "reference": "3e6ccf7657d4f0a59200564b08cead899313b53c", + "shasum": "" + }, + "require": { + "php": ">=8.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/6.0.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-02-07T05:00:38+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "2.0.1", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "reference": "7989e43bf381af0eac72e4f0ca5bcbfa81658be4", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^8.1" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/2.0.1" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2025-12-08T11:19:18+00:00" + } + ], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": ">=8.4.1", + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*" + }, + "platform-dev": {}, + "platform-overrides": { + "php": "8.4.1" + }, + "plugin-api-version": "2.9.0" +} diff --git a/composer/bin/phpunit b/composer/bin/phpunit deleted file mode 100755 index 0c2f0b26aa1..00000000000 --- a/composer/bin/phpunit +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env php -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main'); - -$files = array( - __DIR__ . '/../../vendor/autoload.php', - __DIR__ . '/../../../../autoload.php' -); - -foreach ($files as $file) { - if (file_exists($file)) { - require $file; - - define('PHPUNIT_COMPOSER_INSTALL', $file); - - break; - } -} - -if (!defined('PHPUNIT_COMPOSER_INSTALL')) { - die( - 'You need to set up the project dependencies using the following commands:' . PHP_EOL . - 'curl -s http://getcomposer.org/installer | php' . PHP_EOL . - 'php composer.phar install' . PHP_EOL - ); -} - -PHPUnit_TextUI_Command::main(); diff --git a/package.xml b/package.xml deleted file mode 100644 index b79463decbe..00000000000 --- a/package.xml +++ /dev/null @@ -1,309 +0,0 @@ - - - PHPUnit - pear.phpunit.de - The PHP Unit Testing framework. - The PHP Unit Testing framework. - - Sebastian Bergmann - sb - sebastian@phpunit.de - yes - - 2013-MM-DD - - 3.8.0 - 3.8.0 - - - devel - devel - - The BSD 3-Clause License - http://github.com/sebastianbergmann/phpunit/blob/master/README.md - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5.4.7 - - - 1.9.4 - - - Diff - pear.phpunit.de - 1.0.0 - - - File_Iterator - pear.phpunit.de - 1.3.1 - - - Text_Template - pear.phpunit.de - 1.1.1 - - - PHP_CodeCoverage - pear.phpunit.de - 1.3.0 - 1.3.99 - - - PHP_Timer - pear.phpunit.de - 1.1.0 - - - PHPUnit_MockObject - pear.phpunit.de - 1.3.0 - 1.3.99 - - - Yaml - pear.symfony.com - 2.0.0 - 2.2.99 - - - Version - pear.phpunit.de - 1.0.0 - - - dom - - - pcre - - - - - PHP_Invoker - pear.phpunit.de - 1.2.0 - - - json - - - simplexml - - - tokenizer - - - - - - - windows - - - - - - - - - - - - - - diff --git a/phpdox.xml.dist b/phpdox.xml.dist deleted file mode 100644 index 04af02aa1aa..00000000000 --- a/phpdox.xml.dist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/phpstan.neon b/phpstan.neon new file mode 100644 index 00000000000..57bdb4ea6f2 --- /dev/null +++ b/phpstan.neon @@ -0,0 +1,67 @@ +parameters: + level: 6 + + paths: + - src + + excludePaths: + # exclude partial traits, which are only used in runtime generated code + - src/Framework/MockObject/Runtime/Api + + resultCachePath: %tmpDir%/phpunit-13.0.php + + checkTooWideReturnTypesInProtectedAndPublicMethods: true + reportAlwaysTrueInLastCondition: true + reportPossiblyNonexistentConstantArrayOffset: true + reportPossiblyNonexistentGeneralArrayOffset: true + treatPhpDocTypesAsCertain: false + + strictRules: + allRules: false + booleansInConditions: true + closureUsesThis: true + disallowedBacktick: true + disallowedEmpty: true + disallowedImplicitArrayCreation: true + disallowedLooseComparison: true + disallowedShortTernary: true + illegalConstructorMethodCall: true + matchingInheritedMethodNames: true + noVariableVariables: true + numericOperandsInArithmeticOperators: true + overwriteVariablesWithLoop: true + requireParentConstructorCall: true + strictArrayFilter: true + strictFunctionCalls: true + switchConditionsMatchingType: true + uselessCast: true + + ergebnis: + allRules: false + final: + enabled: true + classesNotRequiredToBeAbstractOrFinal: + - PHPUnit\Framework\Constraint\Count + - PHPUnit\Framework\AssertionFailedError + - PHPUnit\Framework\Exception + - PHPUnit\Framework\TestSuite + privateInFinalClass: + enabled: true + + type_coverage: + declare: 100 + return: 100 + param: 100 + property: 100 + constant: 100 + + ignoreErrors: + # ignore errors caused by defensive programming + - '#Call to function assert\(\) with true will always evaluate to true.#' + - '#Instanceof between .* and .* will always evaluate to true.#' + - '#Strict comparison using !== between .*non-empty-string.* and .* will always evaluate to true.#' + - '#Strict comparison using !== between .*non-falsy-string.* and .* will always evaluate to true.#' + - identifier: argument.named + +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon diff --git a/phpunit b/phpunit new file mode 100755 index 00000000000..7cace6af4ce --- /dev/null +++ b/phpunit @@ -0,0 +1,104 @@ +#!/usr/bin/env php + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!version_compare(PHP_VERSION, PHP_VERSION, '=')) { + fwrite( + STDERR, + sprintf( + '%s declares an invalid value for PHP_VERSION.' . PHP_EOL . + 'This breaks fundamental functionality such as version_compare().' . PHP_EOL . + 'Please use a different PHP interpreter.' . PHP_EOL, + + PHP_BINARY + ) + ); + + die(1); +} + +if (version_compare('8.4.1', PHP_VERSION, '>')) { + fwrite( + STDERR, + sprintf( + 'This version of PHPUnit requires PHP >= 8.4.1.' . PHP_EOL . + 'You are using PHP %s (%s).' . PHP_EOL, + PHP_VERSION, + PHP_BINARY + ) + ); + + die(1); +} + +if (!ini_get('date.timezone')) { + ini_set('date.timezone', 'UTC'); +} + +if (isset($GLOBALS['_composer_autoload_path'])) { + define('PHPUNIT_COMPOSER_INSTALL', $GLOBALS['_composer_autoload_path']); + + unset($GLOBALS['_composer_autoload_path']); +} else { + foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/../vendor/autoload.php', __DIR__ . '/vendor/autoload.php') as $file) { + if (file_exists($file)) { + define('PHPUNIT_COMPOSER_INSTALL', $file); + + break; + } + } + + unset($file); +} + +if (!defined('PHPUNIT_COMPOSER_INSTALL')) { + fwrite( + STDERR, + 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . + ' composer install' . PHP_EOL . PHP_EOL . + 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL + ); + + die(1); +} + +require PHPUNIT_COMPOSER_INSTALL; + +$requiredExtensions = ['dom', 'json', 'libxml', 'mbstring', 'tokenizer', 'xml', 'xmlwriter']; + +$unavailableExtensions = array_filter( + $requiredExtensions, + static function ($extension) { + return !extension_loaded($extension); + } +); + +// Workaround for https://github.com/sebastianbergmann/phpunit/issues/5662 +if (!function_exists('ctype_alnum')) { + $unavailableExtensions[] = 'ctype'; +} + +if ([] !== $unavailableExtensions) { + fwrite( + STDERR, + sprintf( + 'PHPUnit requires the "%s" extensions, but the "%s" %s not available.' . PHP_EOL, + implode('", "', $requiredExtensions), + implode('", "', $unavailableExtensions), + count($unavailableExtensions) === 1 ? 'extension is' : 'extensions are' + ) + ); + + die(1); +} + +unset($requiredExtensions, $unavailableExtensions); + +exit((new PHPUnit\TextUI\Application)->run($_SERVER['argv'])); diff --git a/phpunit.bat b/phpunit.bat deleted file mode 100644 index 29208ec8eb1..00000000000 --- a/phpunit.bat +++ /dev/null @@ -1,43 +0,0 @@ -@echo off -REM PHPUnit -REM -REM Copyright (c) 2002-2010, Sebastian Bergmann . -REM All rights reserved. -REM -REM Redistribution and use in source and binary forms, with or without -REM modification, are permitted provided that the following conditions -REM are met: -REM -REM * Redistributions of source code must retain the above copyright -REM notice, this list of conditions and the following disclaimer. -REM -REM * Redistributions in binary form must reproduce the above copyright -REM notice, this list of conditions and the following disclaimer in -REM the documentation and/or other materials provided with the -REM distribution. -REM -REM * Neither the name of Sebastian Bergmann nor the names of his -REM contributors may be used to endorse or promote products derived -REM from this software without specific prior written permission. -REM -REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -REM FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -REM COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -REM BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC -REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -REM ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -REM POSSIBILITY OF SUCH DAMAGE. -REM - -if "%PHPBIN%" == "" set PHPBIN=@php_bin@ -if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH -GOTO RUN -:USE_PEAR_PATH -set PHPBIN=%PHP_PEAR_PHP_BIN% -:RUN -"%PHPBIN%" "@bin_dir@\phpunit" %* diff --git a/phpunit.php b/phpunit.php deleted file mode 100755 index e3ecc8622e6..00000000000 --- a/phpunit.php +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/env php -. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in - * the documentation and/or other materials provided with the - * distribution. - * - * * Neither the name of Sebastian Bergmann nor the names of his - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS - * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE - * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -define('PHPUnit_MAIN_METHOD', 'PHPUnit_TextUI_Command::main'); - -if (strpos('@php_bin@', '@php_bin') === 0) { - require dirname(__FILE__) . DIRECTORY_SEPARATOR . 'PHPUnit' . DIRECTORY_SEPARATOR . 'Autoload.php'; -} else { - require '@php_dir@' . DIRECTORY_SEPARATOR . 'PHPUnit' . DIRECTORY_SEPARATOR . 'Autoload.php'; -} - -PHPUnit_TextUI_Command::main(); diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000000..088c4197e79 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,67 @@ + + + + + tests/unit + + + + tests/end-to-end/baseline + tests/end-to-end/check-php-configuration + tests/end-to-end/cli + tests/end-to-end/data-provider + tests/end-to-end/deprecation-trigger + tests/end-to-end/event + tests/end-to-end/execution-order + tests/end-to-end/extension-cli + tests/end-to-end/extension-xml + tests/end-to-end/generic + tests/end-to-end/groups-from-configuration + tests/end-to-end/logging/junit + tests/end-to-end/logging/open-test-reporting + tests/end-to-end/logging/teamcity + tests/end-to-end/logging/testdox + tests/end-to-end/metadata + tests/end-to-end/migration + tests/end-to-end/mock-objects + tests/end-to-end/phpt + tests/end-to-end/regression + tests/end-to-end/self-direct-indirect + tests/end-to-end/testdox + + tests/end-to-end/event/_files + tests/end-to-end/execution-order/_files + tests/end-to-end/groups-from-configuration/_files + tests/end-to-end/logging/_files + tests/end-to-end/migration/_files + tests/end-to-end/self-direct-indirect/_files + tests/end-to-end/testdox/_files + + + + + + src + + + + src/Framework/Assert/Functions.php + + + + + + + + + + diff --git a/phpunit.xml.dist b/phpunit.xml.dist deleted file mode 100644 index dc7cb19e6d2..00000000000 --- a/phpunit.xml.dist +++ /dev/null @@ -1,40 +0,0 @@ - - - - - Tests/Framework - Tests/Framework/MockObject - Tests/Extensions - Tests/Regression - Tests/Runner - Tests/TextUI - Tests/Util - - - - - - - - - - - - PHPUnit - - PHPUnit/Autoload.php - PHPUnit/Framework/Assert/Functions.php - - - - - - - - diff --git a/phpunit.xsd b/phpunit.xsd index 0348bc0308a..5a7e1f1404f 100644 --- a/phpunit.xsd +++ b/phpunit.xsd @@ -1,251 +1,352 @@ - - - This Schema file defines the rules by which the XML configuration file of PHPUnit 3.7 may be structured. - - - - - Root Element + + This Schema file defines the rules by which the XML configuration file of PHPUnit 13.0 may be structured. + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The main type specifying the document structure - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.0.xsd b/schema/10.0.xsd new file mode 100644 index 00000000000..480d54decab --- /dev/null +++ b/schema/10.0.xsd @@ -0,0 +1,284 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.1.xsd b/schema/10.1.xsd new file mode 100644 index 00000000000..1b190c21b90 --- /dev/null +++ b/schema/10.1.xsd @@ -0,0 +1,312 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.2.xsd b/schema/10.2.xsd new file mode 100644 index 00000000000..269b7a3aeb4 --- /dev/null +++ b/schema/10.2.xsd @@ -0,0 +1,319 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.3.xsd b/schema/10.3.xsd new file mode 100644 index 00000000000..03a54ee0b08 --- /dev/null +++ b/schema/10.3.xsd @@ -0,0 +1,321 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.4.xsd b/schema/10.4.xsd new file mode 100644 index 00000000000..bd22b2ca2a7 --- /dev/null +++ b/schema/10.4.xsd @@ -0,0 +1,322 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/10.5.xsd b/schema/10.5.xsd new file mode 100644 index 00000000000..284820b0b9c --- /dev/null +++ b/schema/10.5.xsd @@ -0,0 +1,327 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 10.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.0.xsd b/schema/11.0.xsd new file mode 100644 index 00000000000..a6e7cb8cd16 --- /dev/null +++ b/schema/11.0.xsd @@ -0,0 +1,323 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.1.xsd b/schema/11.1.xsd new file mode 100644 index 00000000000..6172e834933 --- /dev/null +++ b/schema/11.1.xsd @@ -0,0 +1,333 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.2.xsd b/schema/11.2.xsd new file mode 100644 index 00000000000..d7c7dcac065 --- /dev/null +++ b/schema/11.2.xsd @@ -0,0 +1,331 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.3.xsd b/schema/11.3.xsd new file mode 100644 index 00000000000..3b30de4d6f7 --- /dev/null +++ b/schema/11.3.xsd @@ -0,0 +1,335 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.4.xsd b/schema/11.4.xsd new file mode 100644 index 00000000000..52db363026a --- /dev/null +++ b/schema/11.4.xsd @@ -0,0 +1,334 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/11.5.xsd b/schema/11.5.xsd new file mode 100644 index 00000000000..ec0227111c9 --- /dev/null +++ b/schema/11.5.xsd @@ -0,0 +1,339 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 11.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.0.xsd b/schema/12.0.xsd new file mode 100644 index 00000000000..c993640f9fb --- /dev/null +++ b/schema/12.0.xsd @@ -0,0 +1,335 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.1.xsd b/schema/12.1.xsd new file mode 100644 index 00000000000..51f225d45ab --- /dev/null +++ b/schema/12.1.xsd @@ -0,0 +1,339 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.1 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.2.xsd b/schema/12.2.xsd new file mode 100644 index 00000000000..9303b643344 --- /dev/null +++ b/schema/12.2.xsd @@ -0,0 +1,347 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.3.xsd b/schema/12.3.xsd new file mode 100644 index 00000000000..73e7c2144ab --- /dev/null +++ b/schema/12.3.xsd @@ -0,0 +1,348 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.4.xsd b/schema/12.4.xsd new file mode 100644 index 00000000000..8a7ce622452 --- /dev/null +++ b/schema/12.4.xsd @@ -0,0 +1,348 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 12.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/12.5.xsd b/schema/12.5.xsd new file mode 100644 index 00000000000..5a7e1f1404f --- /dev/null +++ b/schema/12.5.xsd @@ -0,0 +1,352 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 13.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/8.5.xsd b/schema/8.5.xsd new file mode 100644 index 00000000000..75e22289471 --- /dev/null +++ b/schema/8.5.xsd @@ -0,0 +1,319 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 8.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.0.xsd b/schema/9.0.xsd new file mode 100644 index 00000000000..6db04c09789 --- /dev/null +++ b/schema/9.0.xsd @@ -0,0 +1,315 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.1.xsd b/schema/9.1.xsd new file mode 100644 index 00000000000..b10d30b4619 --- /dev/null +++ b/schema/9.1.xsd @@ -0,0 +1,317 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.0 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.2.xsd b/schema/9.2.xsd new file mode 100644 index 00000000000..d770e8b03bd --- /dev/null +++ b/schema/9.2.xsd @@ -0,0 +1,317 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.2 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.3.xsd b/schema/9.3.xsd new file mode 100644 index 00000000000..638f663ac7b --- /dev/null +++ b/schema/9.3.xsd @@ -0,0 +1,327 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.3 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.4.xsd b/schema/9.4.xsd new file mode 100644 index 00000000000..75a91e832f8 --- /dev/null +++ b/schema/9.4.xsd @@ -0,0 +1,328 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.4 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/schema/9.5.xsd b/schema/9.5.xsd new file mode 100644 index 00000000000..eabefac30b0 --- /dev/null +++ b/schema/9.5.xsd @@ -0,0 +1,330 @@ + + + + + This Schema file defines the rules by which the XML configuration file of PHPUnit 9.5 may be structured. + + + + + + Root Element + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The main type specifying the document structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Event/Dispatcher/CollectingDispatcher.php b/src/Event/Dispatcher/CollectingDispatcher.php new file mode 100644 index 00000000000..e3e9462ee6a --- /dev/null +++ b/src/Event/Dispatcher/CollectingDispatcher.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\DeprecationCollector\TestTriggeredDeprecationSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CollectingDispatcher implements Dispatcher +{ + private EventCollection $events; + private DirectDispatcher $isolatedDirectDispatcher; + + public function __construct(DirectDispatcher $directDispatcher) + { + $this->isolatedDirectDispatcher = $directDispatcher; + $this->events = new EventCollection; + + $this->isolatedDirectDispatcher->registerSubscriber(new TestTriggeredDeprecationSubscriber(DeprecationCollector::collector())); + } + + public function dispatch(Event $event): void + { + $this->events->add($event); + + try { + $this->isolatedDirectDispatcher->dispatch($event); + } catch (UnknownEventTypeException) { + // Do nothing. + } + } + + public function flush(): EventCollection + { + $events = $this->events; + + $this->events = new EventCollection; + + return $events; + } +} diff --git a/src/Event/Dispatcher/DeferringDispatcher.php b/src/Event/Dispatcher/DeferringDispatcher.php new file mode 100644 index 00000000000..6895facb386 --- /dev/null +++ b/src/Event/Dispatcher/DeferringDispatcher.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DeferringDispatcher implements SubscribableDispatcher +{ + private readonly SubscribableDispatcher $dispatcher; + private EventCollection $events; + private bool $recording = true; + + public function __construct(SubscribableDispatcher $dispatcher) + { + $this->dispatcher = $dispatcher; + $this->events = new EventCollection; + } + + public function registerTracer(Tracer\Tracer $tracer): void + { + $this->dispatcher->registerTracer($tracer); + } + + public function registerSubscriber(Subscriber $subscriber): void + { + $this->dispatcher->registerSubscriber($subscriber); + } + + public function dispatch(Event $event): void + { + if ($this->recording) { + $this->events->add($event); + + return; + } + + $this->dispatcher->dispatch($event); + } + + public function flush(): void + { + $this->recording = false; + + foreach ($this->events as $event) { + $this->dispatcher->dispatch($event); + } + + $this->events = new EventCollection; + } +} diff --git a/src/Event/Dispatcher/DirectDispatcher.php b/src/Event/Dispatcher/DirectDispatcher.php new file mode 100644 index 00000000000..b5cbc8e31c1 --- /dev/null +++ b/src/Event/Dispatcher/DirectDispatcher.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use const PHP_EOL; +use function array_key_exists; +use function dirname; +use function sprintf; +use function str_starts_with; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DirectDispatcher implements SubscribableDispatcher +{ + private readonly TypeMap $typeMap; + + /** + * @var array> + */ + private array $subscribers = []; + + /** + * @var list + */ + private array $tracers = []; + + public function __construct(TypeMap $map) + { + $this->typeMap = $map; + } + + public function registerTracer(Tracer\Tracer $tracer): void + { + $this->tracers[] = $tracer; + } + + /** + * @throws MapError + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void + { + if (!$this->typeMap->isKnownSubscriberType($subscriber)) { + throw new UnknownSubscriberTypeException( + sprintf( + 'Subscriber "%s" does not implement any known interface - did you forget to register it?', + $subscriber::class, + ), + ); + } + + $eventClassName = $this->typeMap->map($subscriber); + + if (!array_key_exists($eventClassName, $this->subscribers)) { + $this->subscribers[$eventClassName] = []; + } + + $this->subscribers[$eventClassName][] = $subscriber; + } + + /** + * @throws Throwable + * @throws UnknownEventTypeException + */ + public function dispatch(Event $event): void + { + $eventClassName = $event::class; + + if (!$this->typeMap->isKnownEventType($event)) { + throw new UnknownEventTypeException( + sprintf( + 'Unknown event type "%s"', + $eventClassName, + ), + ); + } + + foreach ($this->tracers as $tracer) { + try { + $tracer->trace($event); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + $this->handleThrowable($t); + } + // @codeCoverageIgnoreEnd + } + + if (!array_key_exists($eventClassName, $this->subscribers)) { + return; + } + + foreach ($this->subscribers[$eventClassName] as $subscriber) { + try { + /** @phpstan-ignore method.notFound */ + $subscriber->notify($event); + } catch (Throwable $t) { + $this->handleThrowable($t); + } + } + } + + /** + * @throws Throwable + */ + public function handleThrowable(Throwable $t): void + { + if ($this->isThrowableFromThirdPartySubscriber($t)) { + Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Exception in third-party event subscriber: %s%s%s', + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString(), + ), + ); + + return; + } + + // @codeCoverageIgnoreStart + throw $t; + // @codeCoverageIgnoreEnd + } + + private function isThrowableFromThirdPartySubscriber(Throwable $t): bool + { + return !str_starts_with($t->getFile(), dirname(__DIR__, 2)); + } +} diff --git a/src/Event/Dispatcher/Dispatcher.php b/src/Event/Dispatcher/Dispatcher.php new file mode 100644 index 00000000000..e7086539539 --- /dev/null +++ b/src/Event/Dispatcher/Dispatcher.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Dispatcher +{ + /** + * @throws UnknownEventTypeException + */ + public function dispatch(Event $event): void; +} diff --git a/src/Event/Dispatcher/SubscribableDispatcher.php b/src/Event/Dispatcher/SubscribableDispatcher.php new file mode 100644 index 00000000000..c4393da1249 --- /dev/null +++ b/src/Event/Dispatcher/SubscribableDispatcher.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface SubscribableDispatcher extends Dispatcher +{ + /** + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void; + + public function registerTracer(Tracer\Tracer $tracer): void; +} diff --git a/src/Event/Emitter/DispatchingEmitter.php b/src/Event/Emitter/DispatchingEmitter.php new file mode 100644 index 00000000000..915222b72ed --- /dev/null +++ b/src/Event/Emitter/DispatchingEmitter.php @@ -0,0 +1,1470 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function assert; +use function memory_reset_peak_usage; +use function preg_match; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Test\DataProviderMethodCalled; +use PHPUnit\Event\Test\DataProviderMethodFinished; +use PHPUnit\Event\TestSuite\Filtered as TestSuiteFiltered; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Loaded as TestSuiteLoaded; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Sorted as TestSuiteSorted; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\IgnorePhpunitWarnings; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\TextUI\Configuration\Configuration; +use SebastianBergmann\Comparator\Comparator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DispatchingEmitter implements Emitter +{ + private readonly Dispatcher $dispatcher; + private readonly Telemetry\System $system; + private readonly Telemetry\Snapshot $startSnapshot; + private Telemetry\Snapshot $previousSnapshot; + + public function __construct(Dispatcher $dispatcher, Telemetry\System $system) + { + $this->dispatcher = $dispatcher; + $this->system = $system; + + $this->startSnapshot = $system->snapshot(); + $this->previousSnapshot = $this->startSnapshot; + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function applicationStarted(): void + { + $this->dispatcher->dispatch( + new Application\Started( + $this->telemetryInfo(), + new Runtime\Runtime, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerStarted(): void + { + $this->dispatcher->dispatch( + new TestRunner\Started( + $this->telemetryInfo(), + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerConfigured(Configuration $configuration): void + { + $this->dispatcher->dispatch( + new TestRunner\Configured( + $this->telemetryInfo(), + $configuration, + ), + ); + } + + /** + * @param non-empty-string $filename + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerBootstrapFinished(string $filename): void + { + $this->dispatcher->dispatch( + new TestRunner\BootstrapFinished( + $this->telemetryInfo(), + $filename, + ), + ); + } + + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerLoadedExtensionFromPhar(string $filename, string $name, string $version): void + { + $this->dispatcher->dispatch( + new TestRunner\ExtensionLoadedFromPhar( + $this->telemetryInfo(), + $filename, + $name, + $version, + ), + ); + } + + /** + * @param class-string $className + * @param array $parameters + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerBootstrappedExtension(string $className, array $parameters): void + { + $this->dispatcher->dispatch( + new TestRunner\ExtensionBootstrapped( + $this->telemetryInfo(), + $className, + $parameters, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function dataProviderMethodCalled(ClassMethod $testMethod, ClassMethod $dataProviderMethod): void + { + $this->dispatcher->dispatch( + new DataProviderMethodCalled( + $this->telemetryInfo(), + $testMethod, + $dataProviderMethod, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function dataProviderMethodFinished(ClassMethod $testMethod, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new DataProviderMethodFinished( + $this->telemetryInfo(), + $testMethod, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteLoaded(TestSuite $testSuite): void + { + $this->dispatcher->dispatch( + new TestSuiteLoaded( + $this->telemetryInfo(), + $testSuite, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteFiltered(TestSuite $testSuite): void + { + $this->dispatcher->dispatch( + new TestSuiteFiltered( + $this->telemetryInfo(), + $testSuite, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void + { + $this->dispatcher->dispatch( + new TestSuiteSorted( + $this->telemetryInfo(), + $executionOrder, + $executionOrderDefects, + $resolveDependencies, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerEventFacadeSealed(): void + { + $this->dispatcher->dispatch( + new TestRunner\EventFacadeSealed( + $this->telemetryInfo(), + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionStarted(TestSuite $testSuite): void + { + $this->dispatcher->dispatch( + new TestRunner\ExecutionStarted( + $this->telemetryInfo(), + $testSuite, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerDisabledGarbageCollection(): void + { + $this->dispatcher->dispatch( + new TestRunner\GarbageCollectionDisabled($this->telemetryInfo()), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredGarbageCollection(): void + { + $this->dispatcher->dispatch( + new TestRunner\GarbageCollectionTriggered($this->telemetryInfo()), + ); + } + + public function childProcessStarted(): void + { + $this->dispatcher->dispatch( + new TestRunner\ChildProcessStarted($this->telemetryInfo()), + ); + } + + public function childProcessErrored(): void + { + $this->dispatcher->dispatch( + new TestRunner\ChildProcessErrored($this->telemetryInfo()), + ); + } + + public function childProcessFinished(string $stdout, string $stderr): void + { + $this->dispatcher->dispatch( + new TestRunner\ChildProcessFinished( + $this->telemetryInfo(), + $stdout, + $stderr, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteSkipped(TestSuite $testSuite, string $message): void + { + $this->dispatcher->dispatch( + new TestSuiteSkipped( + $this->telemetryInfo(), + $testSuite, + $message, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteStarted(TestSuite $testSuite): void + { + $this->dispatcher->dispatch( + new TestSuiteStarted( + $this->telemetryInfo(), + $testSuite, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationStarted(Code\Test $test): void + { + $this->dispatcher->dispatch( + new Test\PreparationStarted( + $this->telemetryInfo(), + $test, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationErrored(Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PreparationErrored( + $this->telemetryInfo(), + $test, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPreparationFailed(Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PreparationFailed( + $this->telemetryInfo(), + $test, + $throwable, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\BeforeFirstTestMethodCalled( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\BeforeFirstTestMethodErrored( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\BeforeFirstTestMethodFailed( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeFirstTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\BeforeFirstTestMethodFinished( + $this->telemetryInfo(), + $testClassName, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\BeforeTestMethodCalled( + $this->telemetryInfo(), + $test, + $calledMethod, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\BeforeTestMethodErrored( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\BeforeTestMethodFailed( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function beforeTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\BeforeTestMethodFinished( + $this->telemetryInfo(), + $test, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\PreConditionCalled( + $this->telemetryInfo(), + $test, + $calledMethod, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PreConditionErrored( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PreConditionFailed( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function preConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\PreConditionFinished( + $this->telemetryInfo(), + $test, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPrepared(Code\Test $test): void + { + memory_reset_peak_usage(); + + $this->dispatcher->dispatch( + new Test\Prepared( + $this->telemetryInfo(), + $test, + ), + ); + } + + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRegisteredComparator(string $className): void + { + $this->dispatcher->dispatch( + new Test\ComparatorRegistered( + $this->telemetryInfo(), + $className, + ), + ); + } + + public function testUsedCustomMethodInvocation(TestMethod $test, ClassMethod $customTestMethodInvocation): void + { + $this->dispatcher->dispatch( + new Test\CustomTestMethodInvocationUsed( + $this->telemetryInfo(), + $test, + $customTestMethodInvocation, + ), + ); + } + + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedMockObject(string $className): void + { + $this->dispatcher->dispatch( + new Test\MockObjectCreated( + $this->telemetryInfo(), + $className, + ), + ); + } + + /** + * @param list $interfaces + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedMockObjectForIntersectionOfInterfaces(array $interfaces): void + { + $this->dispatcher->dispatch( + new Test\MockObjectForIntersectionOfInterfacesCreated( + $this->telemetryInfo(), + $interfaces, + ), + ); + } + + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedPartialMockObject(string $className, string ...$methodNames): void + { + $this->dispatcher->dispatch( + new Test\PartialMockObjectCreated( + $this->telemetryInfo(), + $className, + ...$methodNames, + ), + ); + } + + /** + * @param class-string $className + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedStub(string $className): void + { + $this->dispatcher->dispatch( + new Test\TestStubCreated( + $this->telemetryInfo(), + $className, + ), + ); + } + + /** + * @param list $interfaces + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testCreatedStubForIntersectionOfInterfaces(array $interfaces): void + { + $this->dispatcher->dispatch( + new Test\TestStubForIntersectionOfInterfacesCreated( + $this->telemetryInfo(), + $interfaces, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testErrored(Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\Errored( + $this->telemetryInfo(), + $test, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testFailed(Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure): void + { + $this->dispatcher->dispatch( + new Test\Failed( + $this->telemetryInfo(), + $test, + $throwable, + $comparisonFailure, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPassed(Code\Test $test): void + { + $this->dispatcher->dispatch( + new Test\Passed( + $this->telemetryInfo(), + $test, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testConsideredRisky(Code\Test $test, string $message): void + { + $this->dispatcher->dispatch( + new Test\ConsideredRisky( + $this->telemetryInfo(), + $test, + $message, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testMarkedAsIncomplete(Code\Test $test, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\MarkedIncomplete( + $this->telemetryInfo(), + $test, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSkipped(Code\Test $test, string $message): void + { + $this->dispatcher->dispatch( + new Test\Skipped( + $this->telemetryInfo(), + $test, + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws NoTestCaseObjectOnCallStackException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitDeprecation(?Code\Test $test, string $message): void + { + if ($test === null) { + $test = TestMethodBuilder::fromCallStack(); + } + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + if ($test->metadata()->isIgnorePhpunitDeprecations()->isNotEmpty()) { + return; + } + } + + $this->dispatcher->dispatch( + new Test\PhpunitDeprecationTriggered( + $this->telemetryInfo(), + $test, + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws NoTestCaseObjectOnCallStackException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitNotice(Code\Test $test, string $message): void + { + $this->dispatcher->dispatch( + new Test\PhpunitNoticeTriggered( + $this->telemetryInfo(), + $test, + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpDeprecation(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger): void + { + $this->dispatcher->dispatch( + new Test\PhpDeprecationTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredDeprecation(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace): void + { + $this->dispatcher->dispatch( + new Test\DeprecationTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + $stackTrace, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredError(Code\Test $test, string $message, string $file, int $line, bool $suppressed): void + { + $this->dispatcher->dispatch( + new Test\ErrorTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredNotice(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch( + new Test\NoticeTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpNotice(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch( + new Test\PhpNoticeTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredWarning(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch( + new Test\WarningTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ), + ); + } + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpWarning(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void + { + $this->dispatcher->dispatch( + new Test\PhpWarningTriggered( + $this->telemetryInfo(), + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitError(Code\Test $test, string $message): void + { + $this->dispatcher->dispatch( + new Test\PhpunitErrorTriggered( + $this->telemetryInfo(), + $test, + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testTriggeredPhpunitWarning(Code\Test $test, string $message): void + { + $ignoredByTest = false; + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + $metadata = Registry::parser()->forMethod($test->className(), $test->methodName())->isIgnorePhpunitWarnings()->asArray(); + + if (isset($metadata[0])) { + assert($metadata[0] instanceof IgnorePhpunitWarnings); + + $messagePattern = $metadata[0]->messagePattern(); + + if ($messagePattern === null || (bool) preg_match('{' . $messagePattern . '}', $message)) { + $ignoredByTest = true; + } + } + } + + $this->dispatcher->dispatch( + new Test\PhpunitWarningTriggered( + $this->telemetryInfo(), + $test, + $message, + $ignoredByTest, + ), + ); + } + + /** + * @param non-empty-string $output + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testPrintedUnexpectedOutput(string $output): void + { + $this->dispatcher->dispatch( + new Test\PrintedUnexpectedOutput( + $this->telemetryInfo(), + $output, + ), + ); + } + + /** + * @param non-empty-string $additionalInformation + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testProvidedAdditionalInformation(TestMethod $test, string $additionalInformation): void + { + $this->dispatcher->dispatch( + new Test\AdditionalInformationProvided( + $this->telemetryInfo(), + $test, + $additionalInformation, + ), + ); + } + + /** + * @param non-negative-int $numberOfAssertionsPerformed + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testFinished(Code\Test $test, int $numberOfAssertionsPerformed): void + { + $this->dispatcher->dispatch( + new Test\Finished( + $this->telemetryInfo(), + $test, + $numberOfAssertionsPerformed, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\PostConditionCalled( + $this->telemetryInfo(), + $test, + $calledMethod, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PostConditionErrored( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\PostConditionFailed( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function postConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\PostConditionFinished( + $this->telemetryInfo(), + $test, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\AfterTestMethodCalled( + $this->telemetryInfo(), + $test, + $calledMethod, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\AfterTestMethodErrored( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\AfterTestMethodFailed( + $this->telemetryInfo(), + $test, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\AfterTestMethodFinished( + $this->telemetryInfo(), + $test, + ...$calledMethods, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void + { + $this->dispatcher->dispatch( + new Test\AfterLastTestMethodCalled( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\AfterLastTestMethodErrored( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void + { + $this->dispatcher->dispatch( + new Test\AfterLastTestMethodFailed( + $this->telemetryInfo(), + $testClassName, + $calledMethod, + $throwable, + ), + ); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function afterLastTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void + { + $this->dispatcher->dispatch( + new Test\AfterLastTestMethodFinished( + $this->telemetryInfo(), + $testClassName, + ...$calledMethods, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testSuiteFinished(TestSuite $testSuite): void + { + $this->dispatcher->dispatch( + new TestSuiteFinished( + $this->telemetryInfo(), + $testSuite, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerStartedStaticAnalysisForCodeCoverage(): void + { + $this->dispatcher->dispatch( + new TestRunner\StaticAnalysisForCodeCoverageStarted( + $this->telemetryInfo(), + ), + ); + } + + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerFinishedStaticAnalysisForCodeCoverage(int $cacheHits, int $cacheMisses): void + { + $this->dispatcher->dispatch( + new TestRunner\StaticAnalysisForCodeCoverageFinished( + $this->telemetryInfo(), + $cacheHits, + $cacheMisses, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitDeprecation(string $message): void + { + try { + if (TestMethodBuilder::fromCallStack()->metadata()->isIgnorePhpunitDeprecations()->isNotEmpty()) { + return; + } + } catch (NoTestCaseObjectOnCallStackException) { + } + + $this->dispatcher->dispatch( + new TestRunner\DeprecationTriggered( + $this->telemetryInfo(), + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitNotice(string $message): void + { + $this->dispatcher->dispatch( + new TestRunner\NoticeTriggered( + $this->telemetryInfo(), + $message, + ), + ); + } + + /** + * @param non-empty-string $message + * + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerTriggeredPhpunitWarning(string $message): void + { + $this->dispatcher->dispatch( + new TestRunner\WarningTriggered( + $this->telemetryInfo(), + $message, + ), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerEnabledGarbageCollection(): void + { + $this->dispatcher->dispatch( + new TestRunner\GarbageCollectionEnabled($this->telemetryInfo()), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionAborted(): void + { + $this->dispatcher->dispatch( + new TestRunner\ExecutionAborted($this->telemetryInfo()), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerExecutionFinished(): void + { + $this->dispatcher->dispatch( + new TestRunner\ExecutionFinished($this->telemetryInfo()), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function testRunnerFinished(): void + { + $this->dispatcher->dispatch( + new TestRunner\Finished($this->telemetryInfo()), + ); + } + + /** + * @throws InvalidArgumentException + * @throws UnknownEventTypeException + */ + public function applicationFinished(int $shellExitCode): void + { + $this->dispatcher->dispatch( + new Application\Finished( + $this->telemetryInfo(), + $shellExitCode, + ), + ); + } + + /** + * @throws InvalidArgumentException + */ + private function telemetryInfo(): Telemetry\Info + { + $current = $this->system->snapshot(); + + $info = new Telemetry\Info( + $current, + $current->time()->duration($this->startSnapshot->time()), + $current->memoryUsage()->diff($this->startSnapshot->memoryUsage()), + $current->time()->duration($this->previousSnapshot->time()), + $current->memoryUsage()->diff($this->previousSnapshot->memoryUsage()), + ); + + $this->previousSnapshot = $current; + + return $info; + } +} diff --git a/src/Event/Emitter/Emitter.php b/src/Event/Emitter/Emitter.php new file mode 100644 index 00000000000..da033f1730b --- /dev/null +++ b/src/Event/Emitter/Emitter.php @@ -0,0 +1,333 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\TestSuite\TestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\Configuration\Configuration; +use SebastianBergmann\Comparator\Comparator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Emitter +{ + public function applicationStarted(): void; + + public function testRunnerStarted(): void; + + public function testRunnerConfigured(Configuration $configuration): void; + + /** + * @param non-empty-string $filename + */ + public function testRunnerBootstrapFinished(string $filename): void; + + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + */ + public function testRunnerLoadedExtensionFromPhar(string $filename, string $name, string $version): void; + + /** + * @param class-string $className + * @param array $parameters + */ + public function testRunnerBootstrappedExtension(string $className, array $parameters): void; + + public function dataProviderMethodCalled(ClassMethod $testMethod, ClassMethod $dataProviderMethod): void; + + public function dataProviderMethodFinished(ClassMethod $testMethod, ClassMethod ...$calledMethods): void; + + public function testSuiteLoaded(TestSuite $testSuite): void; + + public function testSuiteFiltered(TestSuite $testSuite): void; + + public function testSuiteSorted(int $executionOrder, int $executionOrderDefects, bool $resolveDependencies): void; + + public function testRunnerEventFacadeSealed(): void; + + public function testRunnerExecutionStarted(TestSuite $testSuite): void; + + public function testRunnerDisabledGarbageCollection(): void; + + public function testRunnerTriggeredGarbageCollection(): void; + + /** + * @param non-empty-string $message + */ + public function testSuiteSkipped(TestSuite $testSuite, string $message): void; + + public function testSuiteStarted(TestSuite $testSuite): void; + + public function testPreparationStarted(Code\Test $test): void; + + public function testPreparationErrored(Code\Test $test, Throwable $throwable): void; + + public function testPreparationFailed(Code\Test $test, Throwable $throwable): void; + + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void; + + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + + /** + * @param class-string $testClassName + */ + public function beforeFirstTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void; + + public function beforeTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void; + + public function beforeTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function beforeTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function beforeTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + + public function preConditionCalled(TestMethod $test, ClassMethod $calledMethod): void; + + public function preConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function preConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function preConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + + public function testPrepared(Code\Test $test): void; + + /** + * @param class-string $className + */ + public function testRegisteredComparator(string $className): void; + + public function testUsedCustomMethodInvocation(TestMethod $test, ClassMethod $customTestMethodInvocation): void; + + /** + * @param class-string $className + */ + public function testCreatedMockObject(string $className): void; + + /** + * @param list $interfaces + */ + public function testCreatedMockObjectForIntersectionOfInterfaces(array $interfaces): void; + + /** + * @param class-string $className + */ + public function testCreatedPartialMockObject(string $className, string ...$methodNames): void; + + /** + * @param class-string $className + */ + public function testCreatedStub(string $className): void; + + /** + * @param list $interfaces + */ + public function testCreatedStubForIntersectionOfInterfaces(array $interfaces): void; + + public function testErrored(Code\Test $test, Throwable $throwable): void; + + public function testFailed(Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure): void; + + public function testPassed(Code\Test $test): void; + + /** + * @param non-empty-string $message + */ + public function testConsideredRisky(Code\Test $test, string $message): void; + + public function testMarkedAsIncomplete(Code\Test $test, Throwable $throwable): void; + + /** + * @param non-empty-string $message + */ + public function testSkipped(Code\Test $test, string $message): void; + + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitDeprecation(?Code\Test $test, string $message): void; + + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitNotice(Code\Test $test, string $message): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpDeprecation(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + */ + public function testTriggeredDeprecation(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredError(Code\Test $test, string $message, string $file, int $line, bool $suppressed): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredNotice(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpNotice(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredWarning(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function testTriggeredPhpWarning(Code\Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline): void; + + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitError(Code\Test $test, string $message): void; + + /** + * @param non-empty-string $message + */ + public function testTriggeredPhpunitWarning(Code\Test $test, string $message): void; + + /** + * @param non-empty-string $output + */ + public function testPrintedUnexpectedOutput(string $output): void; + + /** + * @param non-empty-string $additionalInformation + */ + public function testProvidedAdditionalInformation(TestMethod $test, string $additionalInformation): void; + + /** + * @param non-negative-int $numberOfAssertionsPerformed + */ + public function testFinished(Code\Test $test, int $numberOfAssertionsPerformed): void; + + public function postConditionCalled(TestMethod $test, ClassMethod $calledMethod): void; + + public function postConditionErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function postConditionFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function postConditionFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + + public function afterTestMethodCalled(TestMethod $test, ClassMethod $calledMethod): void; + + public function afterTestMethodErrored(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function afterTestMethodFailed(TestMethod $test, ClassMethod $calledMethod, Throwable $throwable): void; + + public function afterTestMethodFinished(TestMethod $test, ClassMethod ...$calledMethods): void; + + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodCalled(string $testClassName, ClassMethod $calledMethod): void; + + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodErrored(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodFailed(string $testClassName, ClassMethod $calledMethod, Throwable $throwable): void; + + /** + * @param class-string $testClassName + */ + public function afterLastTestMethodFinished(string $testClassName, ClassMethod ...$calledMethods): void; + + public function testSuiteFinished(TestSuite $testSuite): void; + + public function childProcessStarted(): void; + + public function childProcessErrored(): void; + + public function childProcessFinished(string $stdout, string $stderr): void; + + public function testRunnerStartedStaticAnalysisForCodeCoverage(): void; + + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + */ + public function testRunnerFinishedStaticAnalysisForCodeCoverage(int $cacheHits, int $cacheMisses): void; + + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitDeprecation(string $message): void; + + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitNotice(string $message): void; + + /** + * @param non-empty-string $message + */ + public function testRunnerTriggeredPhpunitWarning(string $message): void; + + public function testRunnerEnabledGarbageCollection(): void; + + public function testRunnerExecutionAborted(): void; + + public function testRunnerExecutionFinished(): void; + + public function testRunnerFinished(): void; + + public function applicationFinished(int $shellExitCode): void; +} diff --git a/src/Event/Events/Application/Finished.php b/src/Event/Events/Application/Finished.php new file mode 100644 index 00000000000..6e94da2a957 --- /dev/null +++ b/src/Event/Events/Application/Finished.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private int $shellExitCode; + + public function __construct(Telemetry\Info $telemetryInfo, int $shellExitCode) + { + $this->telemetryInfo = $telemetryInfo; + $this->shellExitCode = $shellExitCode; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function shellExitCode(): int + { + return $this->shellExitCode; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'PHPUnit Finished (Shell Exit Code: %d)', + $this->shellExitCode, + ); + } +} diff --git a/src/Event/Events/Application/FinishedSubscriber.php b/src/Event/Events/Application/FinishedSubscriber.php new file mode 100644 index 00000000000..1e75977617d --- /dev/null +++ b/src/Event/Events/Application/FinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(Finished $event): void; +} diff --git a/src/Event/Events/Application/Started.php b/src/Event/Events/Application/Started.php new file mode 100644 index 00000000000..a9aa959a72a --- /dev/null +++ b/src/Event/Events/Application/Started.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Runtime\Runtime; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + private Runtime $runtime; + + public function __construct(Telemetry\Info $telemetryInfo, Runtime $runtime) + { + $this->telemetryInfo = $telemetryInfo; + $this->runtime = $runtime; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function runtime(): Runtime + { + return $this->runtime; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'PHPUnit Started (%s)', + $this->runtime->asString(), + ); + } +} diff --git a/src/Event/Events/Application/StartedSubscriber.php b/src/Event/Events/Application/StartedSubscriber.php new file mode 100644 index 00000000000..f2ebee2fdbc --- /dev/null +++ b/src/Event/Events/Application/StartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(Started $event): void; +} diff --git a/src/Event/Events/Event.php b/src/Event/Events/Event.php new file mode 100644 index 00000000000..443ca7294a5 --- /dev/null +++ b/src/Event/Events/Event.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Event +{ + public function telemetryInfo(): Telemetry\Info; + + /** + * @return non-empty-string + */ + public function asString(): string; +} diff --git a/src/Event/Events/EventCollection.php b/src/Event/Events/EventCollection.php new file mode 100644 index 00000000000..7c691269294 --- /dev/null +++ b/src/Event/Events/EventCollection.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $events = []; + + public function add(Event ...$events): void + { + foreach ($events as $event) { + $this->events[] = $event; + } + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->events; + } + + public function count(): int + { + return count($this->events); + } + + public function isEmpty(): bool + { + return $this->count() === 0; + } + + public function isNotEmpty(): bool + { + return $this->count() > 0; + } + + public function getIterator(): EventCollectionIterator + { + return new EventCollectionIterator($this); + } +} diff --git a/src/Event/Events/EventCollectionIterator.php b/src/Event/Events/EventCollectionIterator.php new file mode 100644 index 00000000000..d121dea6e40 --- /dev/null +++ b/src/Event/Events/EventCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function count; +use Iterator; + +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $events; + private int $position = 0; + + public function __construct(EventCollection $events) + { + $this->events = $events->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->events); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Event + { + return $this->events[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/Event/Events/Test/AdditionalInformationProvided.php b/src/Event/Events/Test/AdditionalInformationProvided.php new file mode 100644 index 00000000000..d8f819ee407 --- /dev/null +++ b/src/Event/Events/Test/AdditionalInformationProvided.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AdditionalInformationProvided implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestMethod $test; + + /** + * @var non-empty-string + */ + private string $additionalInformation; + + /** + * @param non-empty-string $additionalInformation + */ + public function __construct(Telemetry\Info $telemetryInfo, TestMethod $test, string $additionalInformation) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->additionalInformation = $additionalInformation; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): TestMethod + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function additionalInformation(): string + { + return $this->additionalInformation; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Provided Additional Information%s%s', + PHP_EOL, + $this->additionalInformation, + ); + } +} diff --git a/src/Event/Events/Test/AdditionalInformationProvidedSubscriber.php b/src/Event/Events/Test/AdditionalInformationProvidedSubscriber.php new file mode 100644 index 00000000000..7d175c5945b --- /dev/null +++ b/src/Event/Events/Test/AdditionalInformationProvidedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AdditionalInformationProvidedSubscriber extends Subscriber +{ + public function notify(AdditionalInformationProvided $event): void; +} diff --git a/src/Event/Events/Test/ComparatorRegistered.php b/src/Event/Events/Test/ComparatorRegistered.php new file mode 100644 index 00000000000..9db33d5ea1b --- /dev/null +++ b/src/Event/Events/Test/ComparatorRegistered.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use SebastianBergmann\Comparator\Comparator; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparatorRegistered implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Comparator Registered (%s)', + $this->className, + ); + } +} diff --git a/src/Event/Events/Test/ComparatorRegisteredSubscriber.php b/src/Event/Events/Test/ComparatorRegisteredSubscriber.php new file mode 100644 index 00000000000..10ba78e4faa --- /dev/null +++ b/src/Event/Events/Test/ComparatorRegisteredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ComparatorRegisteredSubscriber extends Subscriber +{ + public function notify(ComparatorRegistered $event): void; +} diff --git a/src/Event/Events/Test/CustomTestMethodInvocationUsed.php b/src/Event/Events/Test/CustomTestMethodInvocationUsed.php new file mode 100644 index 00000000000..65b4d0751cf --- /dev/null +++ b/src/Event/Events/Test/CustomTestMethodInvocationUsed.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CustomTestMethodInvocationUsed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $customTestMethodInvocation; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $customTestMethodInvocation) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->customTestMethodInvocation = $customTestMethodInvocation; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function customTestMethodInvocation(): Code\ClassMethod + { + return $this->customTestMethodInvocation; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Custom Test Method Invocation Used (%s::%s)', + $this->customTestMethodInvocation->className(), + $this->customTestMethodInvocation->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.php b/src/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.php new file mode 100644 index 00000000000..17c3e8da92e --- /dev/null +++ b/src/Event/Events/Test/CustomTestMethodInvocationUsedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface CustomTestMethodInvocationUsedSubscriber extends Subscriber +{ + public function notify(CustomTestMethodInvocationUsed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php new file mode 100644 index 00000000000..2c875a8cfec --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalled.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'After Last Test Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.php new file mode 100644 index 00000000000..08530ab7bf8 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodCalledSubscriber extends Subscriber +{ + public function notify(AfterLastTestMethodCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php new file mode 100644 index 00000000000..ecdb7a15d65 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodErrored.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'After Last Test Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..b994fdeb2f1 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodErroredSubscriber extends Subscriber +{ + public function notify(AfterLastTestMethodErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php new file mode 100644 index 00000000000..b22146ea4a2 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailed.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'After Last Test Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..3b011bd9935 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodFailedSubscriber extends Subscriber +{ + public function notify(AfterLastTestMethodFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php new file mode 100644 index 00000000000..d8a5a11f227 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinished.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + + /** + * @var list + */ + private array $calledMethods; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'After Last Test Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.php new file mode 100644 index 00000000000..0a366b0d86a --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterLastTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(AfterLastTestMethodFinished $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodCalled.php b/src/Event/Events/Test/HookMethod/AfterTestMethodCalled.php new file mode 100644 index 00000000000..ca863a188c2 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodCalled.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'After Test Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.php b/src/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.php new file mode 100644 index 00000000000..3e72fc91c8b --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodCalledSubscriber extends Subscriber +{ + public function notify(AfterTestMethodCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodErrored.php b/src/Event/Events/Test/HookMethod/AfterTestMethodErrored.php new file mode 100644 index 00000000000..ba565fe8b16 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodErrored.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'After Test Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.php b/src/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..622f91625d9 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodErroredSubscriber extends Subscriber +{ + public function notify(AfterTestMethodErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodFailed.php b/src/Event/Events/Test/HookMethod/AfterTestMethodFailed.php new file mode 100644 index 00000000000..e405066f7ef --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodFailed.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'After Test Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.php b/src/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..16134322a63 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodFailedSubscriber extends Subscriber +{ + public function notify(AfterTestMethodFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodFinished.php b/src/Event/Events/Test/HookMethod/AfterTestMethodFinished.php new file mode 100644 index 00000000000..9f5e0429e87 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodFinished.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + + /** + * @var list + */ + private array $calledMethods; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'After Test Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.php new file mode 100644 index 00000000000..5e566889841 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/AfterTestMethodFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface AfterTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(AfterTestMethodFinished $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php new file mode 100644 index 00000000000..b08eb8b95fb --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalled.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Before First Test Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.php new file mode 100644 index 00000000000..a0d4281ff69 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodCalledSubscriber extends Subscriber +{ + public function notify(BeforeFirstTestMethodCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php new file mode 100644 index 00000000000..a2e37b3370f --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErrored.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Before First Test Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..9a1b8754297 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodErroredSubscriber extends Subscriber +{ + public function notify(BeforeFirstTestMethodErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php new file mode 100644 index 00000000000..33e669a4e08 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailed.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Before First Test Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..4e0b7eff7b9 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodFailedSubscriber extends Subscriber +{ + public function notify(BeforeFirstTestMethodFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.php new file mode 100644 index 00000000000..87230a676d2 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinished.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Framework\TestCase; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFinished implements Event +{ + private Telemetry\Info$telemetryInfo; + + /** + * @var class-string + */ + private string $testClassName; + + /** + * @var list + */ + private array $calledMethods; + + /** + * @param class-string $testClassName + */ + public function __construct(Telemetry\Info $telemetryInfo, string $testClassName, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testClassName = $testClassName; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function testClassName(): string + { + return $this->testClassName; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Before First Test Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.php new file mode 100644 index 00000000000..c9f1806419a --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeFirstTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(BeforeFirstTestMethodFinished $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php new file mode 100644 index 00000000000..d9da9311763 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodCalled.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Before Test Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.php new file mode 100644 index 00000000000..5f4e180e67b --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodCalledSubscriber extends Subscriber +{ + public function notify(BeforeTestMethodCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php new file mode 100644 index 00000000000..e6b7cbb195d --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodErrored.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Before Test Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..e53771c4944 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodErroredSubscriber extends Subscriber +{ + public function notify(BeforeTestMethodErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php new file mode 100644 index 00000000000..95b46e4107e --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodFailed.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Before Test Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..0f9f071cea5 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodFailedSubscriber extends Subscriber +{ + public function notify(BeforeTestMethodFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php new file mode 100644 index 00000000000..66d4b7ba16a --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodFinished.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + + /** + * @var list + */ + private array $calledMethods; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Before Test Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.php new file mode 100644 index 00000000000..2a6c758cafd --- /dev/null +++ b/src/Event/Events/Test/HookMethod/BeforeTestMethodFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BeforeTestMethodFinishedSubscriber extends Subscriber +{ + public function notify(BeforeTestMethodFinished $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionCalled.php b/src/Event/Events/Test/HookMethod/PostConditionCalled.php new file mode 100644 index 00000000000..7a9ef804e9b --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionCalled.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionCalled implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Post Condition Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php b/src/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php new file mode 100644 index 00000000000..2c135f50437 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionCalledSubscriber extends Subscriber +{ + public function notify(PostConditionCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionErrored.php b/src/Event/Events/Test/HookMethod/PostConditionErrored.php new file mode 100644 index 00000000000..efb118b0937 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionErrored.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Post Condition Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php b/src/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php new file mode 100644 index 00000000000..7bd2c54ce70 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionErroredSubscriber extends Subscriber +{ + public function notify(PostConditionErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionFailed.php b/src/Event/Events/Test/HookMethod/PostConditionFailed.php new file mode 100644 index 00000000000..cb48689730f --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionFailed.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Post Condition Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php b/src/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php new file mode 100644 index 00000000000..e6ff7557aa0 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionFailedSubscriber extends Subscriber +{ + public function notify(PostConditionFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionFinished.php b/src/Event/Events/Test/HookMethod/PostConditionFinished.php new file mode 100644 index 00000000000..b1d0601a03c --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionFinished.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostConditionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + + /** + * @var list + */ + private array $calledMethods; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Post Condition Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.php new file mode 100644 index 00000000000..f24d9480054 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PostConditionFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PostConditionFinishedSubscriber extends Subscriber +{ + public function notify(PostConditionFinished $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionCalled.php b/src/Event/Events/Test/HookMethod/PreConditionCalled.php new file mode 100644 index 00000000000..c2fd1cd9e15 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionCalled.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionCalled implements Event +{ + private Telemetry\Info$telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Pre Condition Method Called (%s::%s)', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php b/src/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php new file mode 100644 index 00000000000..431dfcc405d --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionCalledSubscriber extends Subscriber +{ + public function notify(PreConditionCalled $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionErrored.php b/src/Event/Events/Test/HookMethod/PreConditionErrored.php new file mode 100644 index 00000000000..9d9001f9510 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionErrored.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Pre Condition Method Errored (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php b/src/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php new file mode 100644 index 00000000000..3465040bbeb --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionErroredSubscriber extends Subscriber +{ + public function notify(PreConditionErrored $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionFailed.php b/src/Event/Events/Test/HookMethod/PreConditionFailed.php new file mode 100644 index 00000000000..bf94de21179 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionFailed.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + private Code\ClassMethod $calledMethod; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod $calledMethod, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethod = $calledMethod; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + public function calledMethod(): Code\ClassMethod + { + return $this->calledMethod; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Pre Condition Method Failed (%s::%s)%s', + $this->calledMethod->className(), + $this->calledMethod->methodName(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php b/src/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php new file mode 100644 index 00000000000..26ce7cdce2c --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionFailedSubscriber extends Subscriber +{ + public function notify(PreConditionFailed $event): void; +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionFinished.php b/src/Event/Events/Test/HookMethod/PreConditionFinished.php new file mode 100644 index 00000000000..922c9d868c4 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionFinished.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreConditionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\TestMethod $test; + + /** + * @var list + */ + private array $calledMethods; + + public function __construct(Telemetry\Info $telemetryInfo, Code\TestMethod $test, Code\ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\TestMethod + { + return $this->test; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = 'Pre Condition Method Finished:'; + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php b/src/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php new file mode 100644 index 00000000000..9c499407e60 --- /dev/null +++ b/src/Event/Events/Test/HookMethod/PreConditionFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreConditionFinishedSubscriber extends Subscriber +{ + public function notify(PreConditionFinished $event): void; +} diff --git a/src/Event/Events/Test/Issue/ConsideredRisky.php b/src/Event/Events/Test/Issue/ConsideredRisky.php new file mode 100644 index 00000000000..306c04e7d50 --- /dev/null +++ b/src/Event/Events/Test/Issue/ConsideredRisky.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConsideredRisky implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Considered Risky (%s)%s%s', + $this->test->id(), + PHP_EOL, + $this->message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/ConsideredRiskySubscriber.php b/src/Event/Events/Test/Issue/ConsideredRiskySubscriber.php new file mode 100644 index 00000000000..a0c714a91ed --- /dev/null +++ b/src/Event/Events/Test/Issue/ConsideredRiskySubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ConsideredRiskySubscriber extends Subscriber +{ + public function notify(ConsideredRisky $event): void; +} diff --git a/src/Event/Events/Test/Issue/DeprecationTriggered.php b/src/Event/Events/Test/Issue/DeprecationTriggered.php new file mode 100644 index 00000000000..09ec56fc8c7 --- /dev/null +++ b/src/Event/Events/Test/Issue/DeprecationTriggered.php @@ -0,0 +1,169 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + private bool $ignoredByTest; + private IssueTrigger $trigger; + + /** + * @var non-empty-string + */ + private string $stackTrace; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $stackTrace + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger, string $stackTrace) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + $this->ignoredByTest = $ignoredByTest; + $this->trigger = $trigger; + $this->stackTrace = $stackTrace; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + + public function trigger(): IssueTrigger + { + return $this->trigger; + } + + /** + * @return non-empty-string + */ + public function stackTrace(): string + { + return $this->stackTrace; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id(), $this->trigger->asString()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered Deprecation (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php b/src/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php new file mode 100644 index 00000000000..e166dbed9e2 --- /dev/null +++ b/src/Event/Events/Test/Issue/DeprecationTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(DeprecationTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/ErrorTriggered.php b/src/Event/Events/Test/Issue/ErrorTriggered.php new file mode 100644 index 00000000000..7faefc634ce --- /dev/null +++ b/src/Event/Events/Test/Issue/ErrorTriggered.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ErrorTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + return sprintf( + 'Test Triggered Error (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php b/src/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php new file mode 100644 index 00000000000..901d88556af --- /dev/null +++ b/src/Event/Events/Test/Issue/ErrorTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ErrorTriggeredSubscriber extends Subscriber +{ + public function notify(ErrorTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/NoticeTriggered.php b/src/Event/Events/Test/Issue/NoticeTriggered.php new file mode 100644 index 00000000000..237e1f18ac8 --- /dev/null +++ b/src/Event/Events/Test/Issue/NoticeTriggered.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered Notice (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php b/src/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php new file mode 100644 index 00000000000..95230d0ff52 --- /dev/null +++ b/src/Event/Events/Test/Issue/NoticeTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface NoticeTriggeredSubscriber extends Subscriber +{ + public function notify(NoticeTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpDeprecationTriggered.php b/src/Event/Events/Test/Issue/PhpDeprecationTriggered.php new file mode 100644 index 00000000000..5b9878ad40f --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpDeprecationTriggered.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpDeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + private bool $ignoredByTest; + private IssueTrigger $trigger; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline, bool $ignoredByTest, IssueTrigger $trigger) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + $this->ignoredByTest = $ignoredByTest; + $this->trigger = $trigger; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + + public function trigger(): IssueTrigger + { + return $this->trigger; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id(), $this->trigger->asString()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered PHP Deprecation (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.php new file mode 100644 index 00000000000..06159a7ce14 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpDeprecationTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpDeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(PhpDeprecationTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpNoticeTriggered.php b/src/Event/Events/Test/Issue/PhpNoticeTriggered.php new file mode 100644 index 00000000000..ad976cfcff2 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpNoticeTriggered.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpNoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered PHP Notice (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php new file mode 100644 index 00000000000..98649bda369 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpNoticeTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpNoticeTriggeredSubscriber extends Subscriber +{ + public function notify(PhpNoticeTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpWarningTriggered.php b/src/Event/Events/Test/Issue/PhpWarningTriggered.php new file mode 100644 index 00000000000..3d65125f753 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpWarningTriggered.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpWarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered PHP Warning (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php new file mode 100644 index 00000000000..3638ba1aa64 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpWarningTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpWarningTriggeredSubscriber extends Subscriber +{ + public function notify(PhpWarningTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpunitDeprecationTriggered.php b/src/Event/Events/Test/Issue/PhpunitDeprecationTriggered.php new file mode 100644 index 00000000000..4e1603f355b --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitDeprecationTriggered.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitDeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Triggered PHPUnit Deprecation (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.php new file mode 100644 index 00000000000..f6b3a239a97 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitDeprecationTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitDeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpunitErrorTriggered.php b/src/Event/Events/Test/Issue/PhpunitErrorTriggered.php new file mode 100644 index 00000000000..abd5e8a1f0b --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitErrorTriggered.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitErrorTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->message); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Triggered PHPUnit Error (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.php new file mode 100644 index 00000000000..e94d1dde262 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitErrorTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitErrorTriggeredSubscriber extends Subscriber +{ + public function notify(PhpunitErrorTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpunitNoticeTriggered.php b/src/Event/Events/Test/Issue/PhpunitNoticeTriggered.php new file mode 100644 index 00000000000..33984ba426b --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitNoticeTriggered.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitNoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->message); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Triggered PHPUnit Notice (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.php new file mode 100644 index 00000000000..0935c6dd350 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitNoticeTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitNoticeTriggeredSubscriber extends Subscriber +{ + public function notify(PhpunitNoticeTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/PhpunitWarningTriggered.php b/src/Event/Events/Test/Issue/PhpunitWarningTriggered.php new file mode 100644 index 00000000000..75ef4894d47 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitWarningTriggered.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpunitWarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + private bool $ignoredByTest; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, bool $ignoredByTest) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->ignoredByTest = $ignoredByTest; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + public function ignoredByTest(): bool + { + return $this->ignoredByTest; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->ignoredByTest) { + $details[] = 'ignored by test'; + } + + return sprintf( + 'Test Triggered PHPUnit Warning (%s)%s', + implode(', ', $details), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.php b/src/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.php new file mode 100644 index 00000000000..72149b2c803 --- /dev/null +++ b/src/Event/Events/Test/Issue/PhpunitWarningTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PhpunitWarningTriggeredSubscriber extends Subscriber +{ + public function notify(PhpunitWarningTriggered $event): void; +} diff --git a/src/Event/Events/Test/Issue/WarningTriggered.php b/src/Event/Events/Test/Issue/WarningTriggered.php new file mode 100644 index 00000000000..7b3e313bf26 --- /dev/null +++ b/src/Event/Events/Test/Issue/WarningTriggered.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function implode; +use function sprintf; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private Test $test; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + private bool $suppressed; + private bool $ignoredByBaseline; + + /** + * @param non-empty-string $message + * @param non-empty-string $file + * @param positive-int $line + */ + public function __construct(Telemetry\Info $telemetryInfo, Test $test, string $message, string $file, int $line, bool $suppressed, bool $ignoredByBaseline) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + $this->file = $file; + $this->line = $line; + $this->suppressed = $suppressed; + $this->ignoredByBaseline = $ignoredByBaseline; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + public function wasSuppressed(): bool + { + return $this->suppressed; + } + + public function ignoredByBaseline(): bool + { + return $this->ignoredByBaseline; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + $details = [$this->test->id()]; + + if ($this->suppressed) { + $details[] = 'suppressed using operator'; + } + + if ($this->ignoredByBaseline) { + $details[] = 'ignored by baseline'; + } + + return sprintf( + 'Test Triggered Warning (%s) in %s:%d%s', + implode(', ', $details), + $this->file, + $this->line, + $message, + ); + } +} diff --git a/src/Event/Events/Test/Issue/WarningTriggeredSubscriber.php b/src/Event/Events/Test/Issue/WarningTriggeredSubscriber.php new file mode 100644 index 00000000000..8eb66648e48 --- /dev/null +++ b/src/Event/Events/Test/Issue/WarningTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface WarningTriggeredSubscriber extends Subscriber +{ + public function notify(WarningTriggered $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php b/src/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php new file mode 100644 index 00000000000..5631e1cf2b1 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/DataProviderMethodCalled.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry\Info; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProviderMethodCalled implements Event +{ + private Info $telemetryInfo; + private ClassMethod $testMethod; + private ClassMethod $dataProviderMethod; + + public function __construct(Info $telemetryInfo, ClassMethod $testMethod, ClassMethod $dataProviderMethod) + { + $this->telemetryInfo = $telemetryInfo; + $this->testMethod = $testMethod; + $this->dataProviderMethod = $dataProviderMethod; + } + + public function telemetryInfo(): Info + { + return $this->telemetryInfo; + } + + public function testMethod(): ClassMethod + { + return $this->testMethod; + } + + public function dataProviderMethod(): ClassMethod + { + return $this->dataProviderMethod; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Data Provider Method Called (%s::%s for test method %s::%s)', + $this->dataProviderMethod->className(), + $this->dataProviderMethod->methodName(), + $this->testMethod->className(), + $this->testMethod->methodName(), + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.php b/src/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.php new file mode 100644 index 00000000000..5f7d4013bb6 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/DataProviderMethodCalledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DataProviderMethodCalledSubscriber extends Subscriber +{ + public function notify(DataProviderMethodCalled $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php b/src/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php new file mode 100644 index 00000000000..ec26779949b --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/DataProviderMethodFinished.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProviderMethodFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private ClassMethod $testMethod; + + /** + * @var list + */ + private array $calledMethods; + + public function __construct(Telemetry\Info $telemetryInfo, ClassMethod $testMethod, ClassMethod ...$calledMethods) + { + $this->telemetryInfo = $telemetryInfo; + $this->testMethod = $testMethod; + $this->calledMethods = $calledMethods; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testMethod(): ClassMethod + { + return $this->testMethod; + } + + /** + * @return list + */ + public function calledMethods(): array + { + return $this->calledMethods; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $buffer = sprintf( + 'Data Provider Method Finished for %s::%s:', + $this->testMethod->className(), + $this->testMethod->methodName(), + ); + + foreach ($this->calledMethods as $calledMethod) { + $buffer .= sprintf( + PHP_EOL . '- %s::%s', + $calledMethod->className(), + $calledMethod->methodName(), + ); + } + + return $buffer; + } +} diff --git a/src/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.php b/src/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.php new file mode 100644 index 00000000000..624f8921d96 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/DataProviderMethodFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DataProviderMethodFinishedSubscriber extends Subscriber +{ + public function notify(DataProviderMethodFinished $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/Finished.php b/src/Event/Events/Test/Lifecycle/Finished.php new file mode 100644 index 00000000000..3cc9a52ffd8 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/Finished.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + + /** + * @var non-negative-int + */ + private int $numberOfAssertionsPerformed; + + /** + * @param non-negative-int $numberOfAssertionsPerformed + */ + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, int $numberOfAssertionsPerformed) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->numberOfAssertionsPerformed = $numberOfAssertionsPerformed; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + /** + * @return non-negative-int + */ + public function numberOfAssertionsPerformed(): int + { + return $this->numberOfAssertionsPerformed; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Finished (%s)', + $this->test->id(), + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/FinishedSubscriber.php b/src/Event/Events/Test/Lifecycle/FinishedSubscriber.php new file mode 100644 index 00000000000..5751e3df7c1 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/FinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(Finished $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationErrored.php b/src/Event/Events/Test/Lifecycle/PreparationErrored.php new file mode 100644 index 00000000000..866bf5f1c4b --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationErrored.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Preparation Errored (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php b/src/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php new file mode 100644 index 00000000000..2cb43d2e838 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationErroredSubscriber extends Subscriber +{ + public function notify(PreparationErrored $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationFailed.php b/src/Event/Events/Test/Lifecycle/PreparationFailed.php new file mode 100644 index 00000000000..7a8b1d67fcc --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationFailed.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationFailed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->throwable->message(); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Preparation Failed (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php b/src/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php new file mode 100644 index 00000000000..da20f11efe7 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationFailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationFailedSubscriber extends Subscriber +{ + public function notify(PreparationFailed $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationStarted.php b/src/Event/Events/Test/Lifecycle/PreparationStarted.php new file mode 100644 index 00000000000..7c548b08b0c --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationStarted.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreparationStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Preparation Started (%s)', + $this->test->id(), + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php b/src/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php new file mode 100644 index 00000000000..f13296b4f4f --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparationStartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparationStartedSubscriber extends Subscriber +{ + public function notify(PreparationStarted $event): void; +} diff --git a/src/Event/Events/Test/Lifecycle/Prepared.php b/src/Event/Events/Test/Lifecycle/Prepared.php new file mode 100644 index 00000000000..d83f1d59570 --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/Prepared.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Prepared implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Prepared (%s)', + $this->test->id(), + ); + } +} diff --git a/src/Event/Events/Test/Lifecycle/PreparedSubscriber.php b/src/Event/Events/Test/Lifecycle/PreparedSubscriber.php new file mode 100644 index 00000000000..f53e227f46e --- /dev/null +++ b/src/Event/Events/Test/Lifecycle/PreparedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PreparedSubscriber extends Subscriber +{ + public function notify(Prepared $event): void; +} diff --git a/src/Event/Events/Test/Outcome/Errored.php b/src/Event/Events/Test/Outcome/Errored.php new file mode 100644 index 00000000000..ef0684989f9 --- /dev/null +++ b/src/Event/Events/Test/Outcome/Errored.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Errored implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Errored (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Outcome/ErroredSubscriber.php b/src/Event/Events/Test/Outcome/ErroredSubscriber.php new file mode 100644 index 00000000000..42dd5b24d58 --- /dev/null +++ b/src/Event/Events/Test/Outcome/ErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ErroredSubscriber extends Subscriber +{ + public function notify(Errored $event): void; +} diff --git a/src/Event/Events/Test/Outcome/Failed.php b/src/Event/Events/Test/Outcome/Failed.php new file mode 100644 index 00000000000..bcc5867f04d --- /dev/null +++ b/src/Event/Events/Test/Outcome/Failed.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Failed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + private ?ComparisonFailure $comparisonFailure; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable, ?ComparisonFailure $comparisonFailure) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + $this->comparisonFailure = $comparisonFailure; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @phpstan-assert-if-true !null $this->comparisonFailure + */ + public function hasComparisonFailure(): bool + { + return $this->comparisonFailure !== null; + } + + /** + * @throws NoComparisonFailureException + */ + public function comparisonFailure(): ComparisonFailure + { + if ($this->comparisonFailure === null) { + throw new NoComparisonFailureException; + } + + return $this->comparisonFailure; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Failed (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Outcome/FailedSubscriber.php b/src/Event/Events/Test/Outcome/FailedSubscriber.php new file mode 100644 index 00000000000..8da6a85f16d --- /dev/null +++ b/src/Event/Events/Test/Outcome/FailedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FailedSubscriber extends Subscriber +{ + public function notify(Failed $event): void; +} diff --git a/src/Event/Events/Test/Outcome/MarkedIncomplete.php b/src/Event/Events/Test/Outcome/MarkedIncomplete.php new file mode 100644 index 00000000000..a69b48a427b --- /dev/null +++ b/src/Event/Events/Test/Outcome/MarkedIncomplete.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use function trim; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MarkedIncomplete implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private Throwable $throwable; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, Throwable $throwable) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->throwable = $throwable; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function throwable(): Throwable + { + return $this->throwable; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = trim($this->throwable->message()); + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Marked Incomplete (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php b/src/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..ff0acd86366 --- /dev/null +++ b/src/Event/Events/Test/Outcome/MarkedIncompleteSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MarkedIncompleteSubscriber extends Subscriber +{ + public function notify(MarkedIncomplete $event): void; +} diff --git a/src/Event/Events/Test/Outcome/Passed.php b/src/Event/Events/Test/Outcome/Passed.php new file mode 100644 index 00000000000..38f2d9816ec --- /dev/null +++ b/src/Event/Events/Test/Outcome/Passed.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Passed implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Passed (%s)', + $this->test->id(), + ); + } +} diff --git a/src/Event/Events/Test/Outcome/PassedSubscriber.php b/src/Event/Events/Test/Outcome/PassedSubscriber.php new file mode 100644 index 00000000000..4a5673816f2 --- /dev/null +++ b/src/Event/Events/Test/Outcome/PassedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PassedSubscriber extends Subscriber +{ + public function notify(Passed $event): void; +} diff --git a/src/Event/Events/Test/Outcome/Skipped.php b/src/Event/Events/Test/Outcome/Skipped.php new file mode 100644 index 00000000000..fe605fff47d --- /dev/null +++ b/src/Event/Events/Test/Outcome/Skipped.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Code; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped implements Event +{ + private Telemetry\Info $telemetryInfo; + private Code\Test $test; + private string $message; + + public function __construct(Telemetry\Info $telemetryInfo, Code\Test $test, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->test = $test; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function test(): Code\Test + { + return $this->test; + } + + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + $message = $this->message; + + if ($message !== '') { + $message = PHP_EOL . $message; + } + + return sprintf( + 'Test Skipped (%s)%s', + $this->test->id(), + $message, + ); + } +} diff --git a/src/Event/Events/Test/Outcome/SkippedSubscriber.php b/src/Event/Events/Test/Outcome/SkippedSubscriber.php new file mode 100644 index 00000000000..5fd48ac6a93 --- /dev/null +++ b/src/Event/Events/Test/Outcome/SkippedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedSubscriber extends Subscriber +{ + public function notify(Skipped $event): void; +} diff --git a/src/Event/Events/Test/PrintedUnexpectedOutput.php b/src/Event/Events/Test/PrintedUnexpectedOutput.php new file mode 100644 index 00000000000..4a0ceab39ac --- /dev/null +++ b/src/Event/Events/Test/PrintedUnexpectedOutput.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PrintedUnexpectedOutput implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-empty-string + */ + private string $output; + + /** + * @param non-empty-string $output + */ + public function __construct(Telemetry\Info $telemetryInfo, string $output) + { + $this->telemetryInfo = $telemetryInfo; + $this->output = $output; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function output(): string + { + return $this->output; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Printed Unexpected Output%s%s', + PHP_EOL, + $this->output, + ); + } +} diff --git a/src/Event/Events/Test/PrintedUnexpectedOutputSubscriber.php b/src/Event/Events/Test/PrintedUnexpectedOutputSubscriber.php new file mode 100644 index 00000000000..ee201572314 --- /dev/null +++ b/src/Event/Events/Test/PrintedUnexpectedOutputSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PrintedUnexpectedOutputSubscriber extends Subscriber +{ + public function notify(PrintedUnexpectedOutput $event): void; +} diff --git a/src/Event/Events/Test/TestDouble/MockObjectCreated.php b/src/Event/Events/Test/TestDouble/MockObjectCreated.php new file mode 100644 index 00000000000..8e91237c4f7 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/MockObjectCreated.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MockObjectCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Mock Object Created (%s)', + $this->className, + ); + } +} diff --git a/src/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php b/src/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php new file mode 100644 index 00000000000..8ad2f176b15 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/MockObjectCreatedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectCreatedSubscriber extends Subscriber +{ + public function notify(MockObjectCreated $event): void; +} diff --git a/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.php b/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.php new file mode 100644 index 00000000000..3548189e8ca --- /dev/null +++ b/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreated.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function implode; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MockObjectForIntersectionOfInterfacesCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var list + */ + private array $interfaces; + + /** + * @param list $interfaces + */ + public function __construct(Telemetry\Info $telemetryInfo, array $interfaces) + { + $this->telemetryInfo = $telemetryInfo; + $this->interfaces = $interfaces; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Mock Object Created (%s)', + implode('&', $this->interfaces), + ); + } +} diff --git a/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.php b/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.php new file mode 100644 index 00000000000..5b345b563f4 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/MockObjectForIntersectionOfInterfacesCreatedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectForIntersectionOfInterfacesCreatedSubscriber extends Subscriber +{ + public function notify(MockObjectForIntersectionOfInterfacesCreated $event): void; +} diff --git a/src/Event/Events/Test/TestDouble/PartialMockObjectCreated.php b/src/Event/Events/Test/TestDouble/PartialMockObjectCreated.php new file mode 100644 index 00000000000..625747816ce --- /dev/null +++ b/src/Event/Events/Test/TestDouble/PartialMockObjectCreated.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PartialMockObjectCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $className; + + /** + * @var list + */ + private array $methodNames; + + /** + * @param class-string $className + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className, string ...$methodNames) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + $this->methodNames = $methodNames; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return list + */ + public function methodNames(): array + { + return $this->methodNames; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Partial Mock Object Created (%s)', + $this->className, + ); + } +} diff --git a/src/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.php b/src/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.php new file mode 100644 index 00000000000..e76407418ed --- /dev/null +++ b/src/Event/Events/Test/TestDouble/PartialMockObjectCreatedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface PartialMockObjectCreatedSubscriber extends Subscriber +{ + public function notify(PartialMockObjectCreated $event): void; +} diff --git a/src/Event/Events/Test/TestDouble/TestStubCreated.php b/src/Event/Events/Test/TestDouble/TestStubCreated.php new file mode 100644 index 00000000000..667fbad4b68 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/TestStubCreated.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestStubCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Stub Created (%s)', + $this->className, + ); + } +} diff --git a/src/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php b/src/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php new file mode 100644 index 00000000000..6b5deaf37c5 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/TestStubCreatedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface TestStubCreatedSubscriber extends Subscriber +{ + public function notify(TestStubCreated $event): void; +} diff --git a/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.php b/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.php new file mode 100644 index 00000000000..bba93d9e02a --- /dev/null +++ b/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreated.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use function implode; +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestStubForIntersectionOfInterfacesCreated implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var list + */ + private array $interfaces; + + /** + * @param list $interfaces + */ + public function __construct(Telemetry\Info $telemetryInfo, array $interfaces) + { + $this->telemetryInfo = $telemetryInfo; + $this->interfaces = $interfaces; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return list + */ + public function interfaces(): array + { + return $this->interfaces; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Stub Created (%s)', + implode('&', $this->interfaces), + ); + } +} diff --git a/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.php b/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.php new file mode 100644 index 00000000000..aec6f66ce36 --- /dev/null +++ b/src/Event/Events/Test/TestDouble/TestStubForIntersectionOfInterfacesCreatedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface TestStubForIntersectionOfInterfacesCreatedSubscriber extends Subscriber +{ + public function notify(TestStubForIntersectionOfInterfacesCreated $event): void; +} diff --git a/src/Event/Events/TestRunner/BootstrapFinished.php b/src/Event/Events/TestRunner/BootstrapFinished.php new file mode 100644 index 00000000000..8e46a00a836 --- /dev/null +++ b/src/Event/Events/TestRunner/BootstrapFinished.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BootstrapFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-empty-string + */ + private string $filename; + + /** + * @param non-empty-string $filename + */ + public function __construct(Telemetry\Info $telemetryInfo, string $filename) + { + $this->telemetryInfo = $telemetryInfo; + $this->filename = $filename; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Bootstrap Finished (%s)', + $this->filename, + ); + } +} diff --git a/src/Event/Events/TestRunner/BootstrapFinishedSubscriber.php b/src/Event/Events/TestRunner/BootstrapFinishedSubscriber.php new file mode 100644 index 00000000000..749648ec49e --- /dev/null +++ b/src/Event/Events/TestRunner/BootstrapFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface BootstrapFinishedSubscriber extends Subscriber +{ + public function notify(BootstrapFinished $event): void; +} diff --git a/src/Event/Events/TestRunner/ChildProcessErrored.php b/src/Event/Events/TestRunner/ChildProcessErrored.php new file mode 100644 index 00000000000..2cb96422b88 --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessErrored.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErrored implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Errored'; + } +} diff --git a/src/Event/Events/TestRunner/ChildProcessErroredSubscriber.php b/src/Event/Events/TestRunner/ChildProcessErroredSubscriber.php new file mode 100644 index 00000000000..6ced5798241 --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessErroredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessErroredSubscriber extends Subscriber +{ + public function notify(ChildProcessErrored $event): void; +} diff --git a/src/Event/Events/TestRunner/ChildProcessFinished.php b/src/Event/Events/TestRunner/ChildProcessFinished.php new file mode 100644 index 00000000000..705a0c63425 --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessFinished.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + private string $stdout; + private string $stderr; + + public function __construct(Telemetry\Info $telemetryInfo, string $stdout, string $stderr) + { + $this->telemetryInfo = $telemetryInfo; + $this->stdout = $stdout; + $this->stderr = $stderr; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function stdout(): string + { + return $this->stdout; + } + + public function stderr(): string + { + return $this->stderr; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Finished'; + } +} diff --git a/src/Event/Events/TestRunner/ChildProcessFinishedSubscriber.php b/src/Event/Events/TestRunner/ChildProcessFinishedSubscriber.php new file mode 100644 index 00000000000..45fefa1827b --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessFinishedSubscriber extends Subscriber +{ + public function notify(ChildProcessFinished $event): void; +} diff --git a/src/Event/Events/TestRunner/ChildProcessStarted.php b/src/Event/Events/TestRunner/ChildProcessStarted.php new file mode 100644 index 00000000000..2c20471e27f --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessStarted.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Child Process Started'; + } +} diff --git a/src/Event/Events/TestRunner/ChildProcessStartedSubscriber.php b/src/Event/Events/TestRunner/ChildProcessStartedSubscriber.php new file mode 100644 index 00000000000..4ba549ce8a0 --- /dev/null +++ b/src/Event/Events/TestRunner/ChildProcessStartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ChildProcessStartedSubscriber extends Subscriber +{ + public function notify(ChildProcessStarted $event): void; +} diff --git a/src/Event/Events/TestRunner/Configured.php b/src/Event/Events/TestRunner/Configured.php new file mode 100644 index 00000000000..e0d14360a3b --- /dev/null +++ b/src/Event/Events/TestRunner/Configured.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\TextUI\Configuration\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Configured implements Event +{ + private Telemetry\Info $telemetryInfo; + private Configuration $configuration; + + public function __construct(Telemetry\Info $telemetryInfo, Configuration $configuration) + { + $this->telemetryInfo = $telemetryInfo; + $this->configuration = $configuration; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function configuration(): Configuration + { + return $this->configuration; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Configured'; + } +} diff --git a/src/Event/Events/TestRunner/ConfiguredSubscriber.php b/src/Event/Events/TestRunner/ConfiguredSubscriber.php new file mode 100644 index 00000000000..0b58f70bf49 --- /dev/null +++ b/src/Event/Events/TestRunner/ConfiguredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ConfiguredSubscriber extends Subscriber +{ + public function notify(Configured $event): void; +} diff --git a/src/Event/Events/TestRunner/DeprecationTriggered.php b/src/Event/Events/TestRunner/DeprecationTriggered.php new file mode 100644 index 00000000000..5cfef8f78cb --- /dev/null +++ b/src/Event/Events/TestRunner/DeprecationTriggered.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DeprecationTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Runner Triggered Deprecation (%s)', + $this->message, + ); + } +} diff --git a/src/Event/Events/TestRunner/DeprecationTriggeredSubscriber.php b/src/Event/Events/TestRunner/DeprecationTriggeredSubscriber.php new file mode 100644 index 00000000000..627ffbd0f0c --- /dev/null +++ b/src/Event/Events/TestRunner/DeprecationTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface DeprecationTriggeredSubscriber extends Subscriber +{ + public function notify(DeprecationTriggered $event): void; +} diff --git a/src/Event/Events/TestRunner/EventFacadeSealed.php b/src/Event/Events/TestRunner/EventFacadeSealed.php new file mode 100644 index 00000000000..bd4f5f60305 --- /dev/null +++ b/src/Event/Events/TestRunner/EventFacadeSealed.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class EventFacadeSealed implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Event Facade Sealed'; + } +} diff --git a/src/Event/Events/TestRunner/EventFacadeSealedSubscriber.php b/src/Event/Events/TestRunner/EventFacadeSealedSubscriber.php new file mode 100644 index 00000000000..4d0d3d01011 --- /dev/null +++ b/src/Event/Events/TestRunner/EventFacadeSealedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface EventFacadeSealedSubscriber extends Subscriber +{ + public function notify(EventFacadeSealed $event): void; +} diff --git a/src/Event/Events/TestRunner/ExecutionAborted.php b/src/Event/Events/TestRunner/ExecutionAborted.php new file mode 100644 index 00000000000..6107e099b57 --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionAborted.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionAborted implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Execution Aborted'; + } +} diff --git a/src/Event/Events/TestRunner/ExecutionAbortedSubscriber.php b/src/Event/Events/TestRunner/ExecutionAbortedSubscriber.php new file mode 100644 index 00000000000..00397cca2e1 --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionAbortedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionAbortedSubscriber extends Subscriber +{ + public function notify(ExecutionAborted $event): void; +} diff --git a/src/Event/Events/TestRunner/ExecutionFinished.php b/src/Event/Events/TestRunner/ExecutionFinished.php new file mode 100644 index 00000000000..25789fe7ca1 --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionFinished.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Execution Finished'; + } +} diff --git a/src/Event/Events/TestRunner/ExecutionFinishedSubscriber.php b/src/Event/Events/TestRunner/ExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..9945fc77e5e --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionFinishedSubscriber extends Subscriber +{ + public function notify(ExecutionFinished $event): void; +} diff --git a/src/Event/Events/TestRunner/ExecutionStarted.php b/src/Event/Events/TestRunner/ExecutionStarted.php new file mode 100644 index 00000000000..e38a2a4d99f --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionStarted.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; +use PHPUnit\Event\TestSuite\TestSuite; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Runner Execution Started (%d test%s)', + $this->testSuite->count(), + $this->testSuite->count() !== 1 ? 's' : '', + ); + } +} diff --git a/src/Event/Events/TestRunner/ExecutionStartedSubscriber.php b/src/Event/Events/TestRunner/ExecutionStartedSubscriber.php new file mode 100644 index 00000000000..532f4409ae2 --- /dev/null +++ b/src/Event/Events/TestRunner/ExecutionStartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExecutionStartedSubscriber extends Subscriber +{ + public function notify(ExecutionStarted $event): void; +} diff --git a/src/Event/Events/TestRunner/ExtensionBootstrapped.php b/src/Event/Events/TestRunner/ExtensionBootstrapped.php new file mode 100644 index 00000000000..4ae1a6d5bd4 --- /dev/null +++ b/src/Event/Events/TestRunner/ExtensionBootstrapped.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionBootstrapped implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var class-string + */ + private string $className; + + /** + * @var array + */ + private array $parameters; + + /** + * @param class-string $className + * @param array $parameters + */ + public function __construct(Telemetry\Info $telemetryInfo, string $className, array $parameters) + { + $this->telemetryInfo = $telemetryInfo; + $this->className = $className; + $this->parameters = $parameters; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Extension Bootstrapped (%s)', + $this->className, + ); + } +} diff --git a/src/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.php b/src/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.php new file mode 100644 index 00000000000..c4c7d55c4b8 --- /dev/null +++ b/src/Event/Events/TestRunner/ExtensionBootstrappedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExtensionBootstrappedSubscriber extends Subscriber +{ + public function notify(ExtensionBootstrapped $event): void; +} diff --git a/src/Event/Events/TestRunner/ExtensionLoadedFromPhar.php b/src/Event/Events/TestRunner/ExtensionLoadedFromPhar.php new file mode 100644 index 00000000000..2ce358d5c75 --- /dev/null +++ b/src/Event/Events/TestRunner/ExtensionLoadedFromPhar.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionLoadedFromPhar implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-empty-string + */ + private string $filename; + + /** + * @var non-empty-string + */ + private string $name; + + /** + * @var non-empty-string + */ + private string $version; + + /** + * @param non-empty-string $filename + * @param non-empty-string $name + * @param non-empty-string $version + */ + public function __construct(Telemetry\Info $telemetryInfo, string $filename, string $name, string $version) + { + $this->telemetryInfo = $telemetryInfo; + $this->filename = $filename; + $this->name = $name; + $this->version = $version; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + + /** + * @return non-empty-string + */ + public function version(): string + { + return $this->version; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Extension Loaded from PHAR (%s %s)', + $this->name, + $this->version, + ); + } +} diff --git a/src/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.php b/src/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.php new file mode 100644 index 00000000000..fc7c2b0abef --- /dev/null +++ b/src/Event/Events/TestRunner/ExtensionLoadedFromPharSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ExtensionLoadedFromPharSubscriber extends Subscriber +{ + public function notify(ExtensionLoadedFromPhar $event): void; +} diff --git a/src/Event/Events/TestRunner/Finished.php b/src/Event/Events/TestRunner/Finished.php new file mode 100644 index 00000000000..2abc685bb9e --- /dev/null +++ b/src/Event/Events/TestRunner/Finished.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Finished'; + } +} diff --git a/src/Event/Events/TestRunner/FinishedSubscriber.php b/src/Event/Events/TestRunner/FinishedSubscriber.php new file mode 100644 index 00000000000..6efc622d0b7 --- /dev/null +++ b/src/Event/Events/TestRunner/FinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(Finished $event): void; +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionDisabled.php b/src/Event/Events/TestRunner/GarbageCollectionDisabled.php new file mode 100644 index 00000000000..4324a5c157c --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionDisabled.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionDisabled implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Disabled Garbage Collection'; + } +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.php b/src/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.php new file mode 100644 index 00000000000..bb7e224fc65 --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionDisabledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionDisabledSubscriber extends Subscriber +{ + public function notify(GarbageCollectionDisabled $event): void; +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionEnabled.php b/src/Event/Events/TestRunner/GarbageCollectionEnabled.php new file mode 100644 index 00000000000..1c4e088874f --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionEnabled.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionEnabled implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Enabled Garbage Collection'; + } +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.php b/src/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.php new file mode 100644 index 00000000000..437eddc231e --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionEnabledSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionEnabledSubscriber extends Subscriber +{ + public function notify(GarbageCollectionEnabled $event): void; +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionTriggered.php b/src/Event/Events/TestRunner/GarbageCollectionTriggered.php new file mode 100644 index 00000000000..d6a1ce643a9 --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionTriggered.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectionTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Triggered Garbage Collection'; + } +} diff --git a/src/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.php b/src/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.php new file mode 100644 index 00000000000..8b941c53580 --- /dev/null +++ b/src/Event/Events/TestRunner/GarbageCollectionTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectionTriggeredSubscriber extends Subscriber +{ + public function notify(GarbageCollectionTriggered $event): void; +} diff --git a/src/Event/Events/TestRunner/NoticeTriggered.php b/src/Event/Events/TestRunner/NoticeTriggered.php new file mode 100644 index 00000000000..a5bfa04f386 --- /dev/null +++ b/src/Event/Events/TestRunner/NoticeTriggered.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NoticeTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + private string $message; + + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Runner Triggered Notice (%s)', + $this->message, + ); + } +} diff --git a/src/Event/Events/TestRunner/NoticeTriggeredSubscriber.php b/src/Event/Events/TestRunner/NoticeTriggeredSubscriber.php new file mode 100644 index 00000000000..be76b2c639e --- /dev/null +++ b/src/Event/Events/TestRunner/NoticeTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface NoticeTriggeredSubscriber extends Subscriber +{ + public function notify(NoticeTriggered $event): void; +} diff --git a/src/Event/Events/TestRunner/Started.php b/src/Event/Events/TestRunner/Started.php new file mode 100644 index 00000000000..a5840110850 --- /dev/null +++ b/src/Event/Events/TestRunner/Started.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Runner Started'; + } +} diff --git a/src/Event/Events/TestRunner/StartedSubscriber.php b/src/Event/Events/TestRunner/StartedSubscriber.php new file mode 100644 index 00000000000..342407031d5 --- /dev/null +++ b/src/Event/Events/TestRunner/StartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(Started $event): void; +} diff --git a/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php new file mode 100644 index 00000000000..d484528ec9c --- /dev/null +++ b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinished.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class StaticAnalysisForCodeCoverageFinished implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-negative-int + */ + private int $cacheHits; + + /** + * @var non-negative-int + */ + private int $cacheMisses; + + /** + * @param non-negative-int $cacheHits + * @param non-negative-int $cacheMisses + */ + public function __construct(Telemetry\Info $telemetryInfo, int $cacheHits, int $cacheMisses) + { + $this->telemetryInfo = $telemetryInfo; + $this->cacheHits = $cacheHits; + $this->cacheMisses = $cacheMisses; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-negative-int + */ + public function cacheHits(): int + { + return $this->cacheHits; + } + + /** + * @return non-negative-int + */ + public function cacheMisses(): int + { + return $this->cacheMisses; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Static Analysis for Code Coverage Finished (%d cache hits, %d cache misses)', + $this->cacheHits, + $this->cacheMisses, + ); + } +} diff --git a/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.php b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.php new file mode 100644 index 00000000000..eaf4f34856e --- /dev/null +++ b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StaticAnalysisForCodeCoverageFinishedSubscriber extends Subscriber +{ + public function notify(StaticAnalysisForCodeCoverageFinished $event): void; +} diff --git a/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.php b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.php new file mode 100644 index 00000000000..d121097272e --- /dev/null +++ b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStarted.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class StaticAnalysisForCodeCoverageStarted implements Event +{ + private Telemetry\Info $telemetryInfo; + + public function __construct(Telemetry\Info $telemetryInfo) + { + $this->telemetryInfo = $telemetryInfo; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Static Analysis for Code Coverage Started'; + } +} diff --git a/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.php b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.php new file mode 100644 index 00000000000..642bf712c80 --- /dev/null +++ b/src/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StaticAnalysisForCodeCoverageStartedSubscriber extends Subscriber +{ + public function notify(StaticAnalysisForCodeCoverageStarted $event): void; +} diff --git a/src/Event/Events/TestRunner/WarningTriggered.php b/src/Event/Events/TestRunner/WarningTriggered.php new file mode 100644 index 00000000000..e9df01be971 --- /dev/null +++ b/src/Event/Events/TestRunner/WarningTriggered.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WarningTriggered implements Event +{ + private Telemetry\Info $telemetryInfo; + + /** + * @var non-empty-string + */ + private string $message; + + /** + * @param non-empty-string $message + */ + public function __construct(Telemetry\Info $telemetryInfo, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + /** + * @return non-empty-string + */ + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Runner Triggered Warning (%s)', + $this->message, + ); + } +} diff --git a/src/Event/Events/TestRunner/WarningTriggeredSubscriber.php b/src/Event/Events/TestRunner/WarningTriggeredSubscriber.php new file mode 100644 index 00000000000..9afdd18f341 --- /dev/null +++ b/src/Event/Events/TestRunner/WarningTriggeredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface WarningTriggeredSubscriber extends Subscriber +{ + public function notify(WarningTriggered $event): void; +} diff --git a/src/Event/Events/TestSuite/Filtered.php b/src/Event/Events/TestSuite/Filtered.php new file mode 100644 index 00000000000..96d626ce4ef --- /dev/null +++ b/src/Event/Events/TestSuite/Filtered.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filtered implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Suite Filtered (%d test%s)', + $this->testSuite->count(), + $this->testSuite->count() !== 1 ? 's' : '', + ); + } +} diff --git a/src/Event/Events/TestSuite/FilteredSubscriber.php b/src/Event/Events/TestSuite/FilteredSubscriber.php new file mode 100644 index 00000000000..6bba3ad4030 --- /dev/null +++ b/src/Event/Events/TestSuite/FilteredSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FilteredSubscriber extends Subscriber +{ + public function notify(Filtered $event): void; +} diff --git a/src/Event/Events/TestSuite/Finished.php b/src/Event/Events/TestSuite/Finished.php new file mode 100644 index 00000000000..a24ca869296 --- /dev/null +++ b/src/Event/Events/TestSuite/Finished.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Finished implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Suite Finished (%s, %d test%s)', + $this->testSuite->name(), + $this->testSuite->count(), + $this->testSuite->count() !== 1 ? 's' : '', + ); + } +} diff --git a/src/Event/Events/TestSuite/FinishedSubscriber.php b/src/Event/Events/TestSuite/FinishedSubscriber.php new file mode 100644 index 00000000000..463c62136ff --- /dev/null +++ b/src/Event/Events/TestSuite/FinishedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface FinishedSubscriber extends Subscriber +{ + public function notify(Finished $event): void; +} diff --git a/src/Event/Events/TestSuite/Loaded.php b/src/Event/Events/TestSuite/Loaded.php new file mode 100644 index 00000000000..d278c0ddc04 --- /dev/null +++ b/src/Event/Events/TestSuite/Loaded.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loaded implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Suite Loaded (%d test%s)', + $this->testSuite->count(), + $this->testSuite->count() !== 1 ? 's' : '', + ); + } +} diff --git a/src/Event/Events/TestSuite/LoadedSubscriber.php b/src/Event/Events/TestSuite/LoadedSubscriber.php new file mode 100644 index 00000000000..e43886c4023 --- /dev/null +++ b/src/Event/Events/TestSuite/LoadedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface LoadedSubscriber extends Subscriber +{ + public function notify(Loaded $event): void; +} diff --git a/src/Event/Events/TestSuite/Skipped.php b/src/Event/Events/TestSuite/Skipped.php new file mode 100644 index 00000000000..efe9c1fff1a --- /dev/null +++ b/src/Event/Events/TestSuite/Skipped.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + private string $message; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite, string $message) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + $this->message = $message; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + public function message(): string + { + return $this->message; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Suite Skipped (%s, %s)', + $this->testSuite->name(), + $this->message, + ); + } +} diff --git a/src/Event/Events/TestSuite/SkippedSubscriber.php b/src/Event/Events/TestSuite/SkippedSubscriber.php new file mode 100644 index 00000000000..30f509fc691 --- /dev/null +++ b/src/Event/Events/TestSuite/SkippedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedSubscriber extends Subscriber +{ + public function notify(Skipped $event): void; +} diff --git a/src/Event/Events/TestSuite/Sorted.php b/src/Event/Events/TestSuite/Sorted.php new file mode 100644 index 00000000000..a73461db8bf --- /dev/null +++ b/src/Event/Events/TestSuite/Sorted.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Sorted implements Event +{ + private Telemetry\Info $telemetryInfo; + private int $executionOrder; + private int $executionOrderDefects; + private bool $resolveDependencies; + + public function __construct(Telemetry\Info $telemetryInfo, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies) + { + $this->telemetryInfo = $telemetryInfo; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->resolveDependencies = $resolveDependencies; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function executionOrder(): int + { + return $this->executionOrder; + } + + public function executionOrderDefects(): int + { + return $this->executionOrderDefects; + } + + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return 'Test Suite Sorted'; + } +} diff --git a/src/Event/Events/TestSuite/SortedSubscriber.php b/src/Event/Events/TestSuite/SortedSubscriber.php new file mode 100644 index 00000000000..481eabb04dc --- /dev/null +++ b/src/Event/Events/TestSuite/SortedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface SortedSubscriber extends Subscriber +{ + public function notify(Sorted $event): void; +} diff --git a/src/Event/Events/TestSuite/Started.php b/src/Event/Events/TestSuite/Started.php new file mode 100644 index 00000000000..36fee1f0065 --- /dev/null +++ b/src/Event/Events/TestSuite/Started.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function sprintf; +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Started implements Event +{ + private Telemetry\Info $telemetryInfo; + private TestSuite $testSuite; + + public function __construct(Telemetry\Info $telemetryInfo, TestSuite $testSuite) + { + $this->telemetryInfo = $telemetryInfo; + $this->testSuite = $testSuite; + } + + public function telemetryInfo(): Telemetry\Info + { + return $this->telemetryInfo; + } + + public function testSuite(): TestSuite + { + return $this->testSuite; + } + + /** + * @return non-empty-string + */ + public function asString(): string + { + return sprintf( + 'Test Suite Started (%s, %d test%s)', + $this->testSuite->name(), + $this->testSuite->count(), + $this->testSuite->count() !== 1 ? 's' : '', + ); + } +} diff --git a/src/Event/Events/TestSuite/StartedSubscriber.php b/src/Event/Events/TestSuite/StartedSubscriber.php new file mode 100644 index 00000000000..66c4e1b2dbc --- /dev/null +++ b/src/Event/Events/TestSuite/StartedSubscriber.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Subscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface StartedSubscriber extends Subscriber +{ + public function notify(Started $event): void; +} diff --git a/src/Event/Exception/EventAlreadyAssignedException.php b/src/Event/Exception/EventAlreadyAssignedException.php new file mode 100644 index 00000000000..a7dba264c45 --- /dev/null +++ b/src/Event/Exception/EventAlreadyAssignedException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventAlreadyAssignedException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/EventFacadeIsSealedException.php b/src/Event/Exception/EventFacadeIsSealedException.php new file mode 100644 index 00000000000..96bf949d92a --- /dev/null +++ b/src/Event/Exception/EventFacadeIsSealedException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class EventFacadeIsSealedException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/Exception.php b/src/Event/Exception/Exception.php new file mode 100644 index 00000000000..25bf06c6b39 --- /dev/null +++ b/src/Event/Exception/Exception.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} diff --git a/src/Event/Exception/InvalidArgumentException.php b/src/Event/Exception/InvalidArgumentException.php new file mode 100644 index 00000000000..3fb060cf75d --- /dev/null +++ b/src/Event/Exception/InvalidArgumentException.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidArgumentException extends \InvalidArgumentException implements Exception +{ +} diff --git a/src/Event/Exception/InvalidEventException.php b/src/Event/Exception/InvalidEventException.php new file mode 100644 index 00000000000..05290372f5a --- /dev/null +++ b/src/Event/Exception/InvalidEventException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidEventException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/InvalidSubscriberException.php b/src/Event/Exception/InvalidSubscriberException.php new file mode 100644 index 00000000000..d12deb7f1ae --- /dev/null +++ b/src/Event/Exception/InvalidSubscriberException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidSubscriberException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/MapError.php b/src/Event/Exception/MapError.php new file mode 100644 index 00000000000..b97a18e6bcc --- /dev/null +++ b/src/Event/Exception/MapError.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MapError extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/NoComparisonFailureException.php b/src/Event/Exception/NoComparisonFailureException.php new file mode 100644 index 00000000000..f9926772c65 --- /dev/null +++ b/src/Event/Exception/NoComparisonFailureException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoComparisonFailureException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/NoDataSetFromDataProviderException.php b/src/Event/Exception/NoDataSetFromDataProviderException.php new file mode 100644 index 00000000000..b17a4d154f0 --- /dev/null +++ b/src/Event/Exception/NoDataSetFromDataProviderException.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use PHPUnit\Event\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoDataSetFromDataProviderException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/NoPreviousThrowableException.php b/src/Event/Exception/NoPreviousThrowableException.php new file mode 100644 index 00000000000..e339323cd41 --- /dev/null +++ b/src/Event/Exception/NoPreviousThrowableException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoPreviousThrowableException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/NoTestCaseObjectOnCallStackException.php b/src/Event/Exception/NoTestCaseObjectOnCallStackException.php new file mode 100644 index 00000000000..35b4c25af75 --- /dev/null +++ b/src/Event/Exception/NoTestCaseObjectOnCallStackException.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Event\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoTestCaseObjectOnCallStackException extends RuntimeException implements Exception +{ + public function __construct() + { + parent::__construct('Cannot find TestCase object on call stack'); + } +} diff --git a/src/Event/Exception/RuntimeException.php b/src/Event/Exception/RuntimeException.php new file mode 100644 index 00000000000..2a444db2fa6 --- /dev/null +++ b/src/Event/Exception/RuntimeException.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/SubscriberTypeAlreadyRegisteredException.php b/src/Event/Exception/SubscriberTypeAlreadyRegisteredException.php new file mode 100644 index 00000000000..ebbbd3fa0aa --- /dev/null +++ b/src/Event/Exception/SubscriberTypeAlreadyRegisteredException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class SubscriberTypeAlreadyRegisteredException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/UnknownEventException.php b/src/Event/Exception/UnknownEventException.php new file mode 100644 index 00000000000..0c1211473f0 --- /dev/null +++ b/src/Event/Exception/UnknownEventException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownEventException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/UnknownEventTypeException.php b/src/Event/Exception/UnknownEventTypeException.php new file mode 100644 index 00000000000..ab9432decc5 --- /dev/null +++ b/src/Event/Exception/UnknownEventTypeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownEventTypeException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/UnknownSubscriberException.php b/src/Event/Exception/UnknownSubscriberException.php new file mode 100644 index 00000000000..b9aaedb1db4 --- /dev/null +++ b/src/Event/Exception/UnknownSubscriberException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownSubscriberException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Exception/UnknownSubscriberTypeException.php b/src/Event/Exception/UnknownSubscriberTypeException.php new file mode 100644 index 00000000000..d44ff0e9c8a --- /dev/null +++ b/src/Event/Exception/UnknownSubscriberTypeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownSubscriberTypeException extends RuntimeException implements Exception +{ +} diff --git a/src/Event/Facade.php b/src/Event/Facade.php new file mode 100644 index 00000000000..946292cb20a --- /dev/null +++ b/src/Event/Facade.php @@ -0,0 +1,275 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function assert; +use function interface_exists; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Telemetry\SystemGarbageCollectorStatusProvider; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?self $instance = null; + private Emitter $emitter; + private ?TypeMap $typeMap = null; + private ?DeferringDispatcher $deferringDispatcher = null; + private bool $sealed = false; + + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self; + } + + return self::$instance; + } + + public static function emitter(): Emitter + { + return self::instance()->emitter; + } + + public function __construct() + { + $this->emitter = $this->createDispatchingEmitter(); + } + + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscribers(Subscriber ...$subscribers): void + { + foreach ($subscribers as $subscriber) { + $this->registerSubscriber($subscriber); + } + } + + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void + { + if ($this->sealed) { + throw new EventFacadeIsSealedException; + } + + $this->deferredDispatcher()->registerSubscriber($subscriber); + } + + /** + * @throws EventFacadeIsSealedException + */ + public function registerTracer(Tracer\Tracer $tracer): void + { + if ($this->sealed) { + throw new EventFacadeIsSealedException; + } + + $this->deferredDispatcher()->registerTracer($tracer); + } + + /** + * @codeCoverageIgnore + * + * @noinspection PhpUnused + */ + public function initForIsolation(HRTime $offset): CollectingDispatcher + { + DeprecationCollector::initForIsolation(); + + $dispatcher = new CollectingDispatcher( + new DirectDispatcher($this->typeMap()), + ); + + $this->emitter = new DispatchingEmitter( + $dispatcher, + new Telemetry\System( + new Telemetry\SystemStopWatchWithOffset($offset), + new Telemetry\SystemMemoryMeter, + new SystemGarbageCollectorStatusProvider, + ), + ); + + $this->sealed = true; + + return $dispatcher; + } + + public function forward(EventCollection $events): void + { + $dispatcher = $this->deferredDispatcher(); + + foreach ($events as $event) { + $dispatcher->dispatch($event); + } + } + + public function seal(): void + { + $this->deferredDispatcher()->flush(); + + $this->sealed = true; + + $this->emitter->testRunnerEventFacadeSealed(); + } + + private function createDispatchingEmitter(): DispatchingEmitter + { + return new DispatchingEmitter( + $this->deferredDispatcher(), + $this->createTelemetrySystem(), + ); + } + + private function createTelemetrySystem(): Telemetry\System + { + return new Telemetry\System( + new Telemetry\SystemStopWatch, + new Telemetry\SystemMemoryMeter, + new SystemGarbageCollectorStatusProvider, + ); + } + + private function deferredDispatcher(): DeferringDispatcher + { + if ($this->deferringDispatcher === null) { + $this->deferringDispatcher = new DeferringDispatcher( + new DirectDispatcher($this->typeMap()), + ); + } + + return $this->deferringDispatcher; + } + + private function typeMap(): TypeMap + { + if ($this->typeMap === null) { + $typeMap = new TypeMap; + + $this->registerDefaultTypes($typeMap); + + $this->typeMap = $typeMap; + } + + return $this->typeMap; + } + + private function registerDefaultTypes(TypeMap $typeMap): void + { + $defaultEvents = [ + Application\Started::class, + Application\Finished::class, + + Test\DataProviderMethodCalled::class, + Test\DataProviderMethodFinished::class, + Test\MarkedIncomplete::class, + Test\AfterLastTestMethodCalled::class, + Test\AfterLastTestMethodErrored::class, + Test\AfterLastTestMethodFailed::class, + Test\AfterLastTestMethodFinished::class, + Test\AfterTestMethodCalled::class, + Test\AfterTestMethodErrored::class, + Test\AfterTestMethodFailed::class, + Test\AfterTestMethodFinished::class, + Test\BeforeFirstTestMethodCalled::class, + Test\BeforeFirstTestMethodErrored::class, + Test\BeforeFirstTestMethodFailed::class, + Test\BeforeFirstTestMethodFinished::class, + Test\BeforeTestMethodCalled::class, + Test\BeforeTestMethodErrored::class, + Test\BeforeTestMethodFailed::class, + Test\BeforeTestMethodFinished::class, + Test\AdditionalInformationProvided::class, + Test\ComparatorRegistered::class, + Test\CustomTestMethodInvocationUsed::class, + Test\ConsideredRisky::class, + Test\DeprecationTriggered::class, + Test\Errored::class, + Test\ErrorTriggered::class, + Test\Failed::class, + Test\Finished::class, + Test\NoticeTriggered::class, + Test\Passed::class, + Test\PhpDeprecationTriggered::class, + Test\PhpNoticeTriggered::class, + Test\PhpunitDeprecationTriggered::class, + Test\PhpunitNoticeTriggered::class, + Test\PhpunitErrorTriggered::class, + Test\PhpunitWarningTriggered::class, + Test\PhpWarningTriggered::class, + Test\PostConditionCalled::class, + Test\PostConditionErrored::class, + Test\PostConditionFailed::class, + Test\PostConditionFinished::class, + Test\PreConditionCalled::class, + Test\PreConditionErrored::class, + Test\PreConditionFailed::class, + Test\PreConditionFinished::class, + Test\PreparationStarted::class, + Test\Prepared::class, + Test\PreparationErrored::class, + Test\PreparationFailed::class, + Test\PrintedUnexpectedOutput::class, + Test\Skipped::class, + Test\WarningTriggered::class, + + Test\MockObjectCreated::class, + Test\MockObjectForIntersectionOfInterfacesCreated::class, + Test\PartialMockObjectCreated::class, + Test\TestStubCreated::class, + Test\TestStubForIntersectionOfInterfacesCreated::class, + + TestRunner\BootstrapFinished::class, + TestRunner\Configured::class, + TestRunner\EventFacadeSealed::class, + TestRunner\ExecutionAborted::class, + TestRunner\ExecutionFinished::class, + TestRunner\ExecutionStarted::class, + TestRunner\ExtensionLoadedFromPhar::class, + TestRunner\ExtensionBootstrapped::class, + TestRunner\Finished::class, + TestRunner\Started::class, + TestRunner\DeprecationTriggered::class, + TestRunner\NoticeTriggered::class, + TestRunner\WarningTriggered::class, + TestRunner\GarbageCollectionDisabled::class, + TestRunner\GarbageCollectionTriggered::class, + TestRunner\GarbageCollectionEnabled::class, + TestRunner\ChildProcessStarted::class, + TestRunner\ChildProcessErrored::class, + TestRunner\ChildProcessFinished::class, + TestRunner\StaticAnalysisForCodeCoverageFinished::class, + TestRunner\StaticAnalysisForCodeCoverageStarted::class, + + TestSuite\Filtered::class, + TestSuite\Finished::class, + TestSuite\Loaded::class, + TestSuite\Skipped::class, + TestSuite\Sorted::class, + TestSuite\Started::class, + ]; + + foreach ($defaultEvents as $eventClass) { + $subscriberInterface = $eventClass . 'Subscriber'; + + assert(interface_exists($subscriberInterface)); + + $typeMap->addMapping($subscriberInterface, $eventClass); + } + } +} diff --git a/src/Event/Subscriber.php b/src/Event/Subscriber.php new file mode 100644 index 00000000000..e0455c025ca --- /dev/null +++ b/src/Event/Subscriber.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Subscriber +{ +} diff --git a/src/Event/Tracer.php b/src/Event/Tracer.php new file mode 100644 index 00000000000..3b029fdf217 --- /dev/null +++ b/src/Event/Tracer.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Tracer; + +use PHPUnit\Event\Event; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Tracer +{ + public function trace(Event $event): void; +} diff --git a/src/Event/TypeMap.php b/src/Event/TypeMap.php new file mode 100644 index 00000000000..08f42a42094 --- /dev/null +++ b/src/Event/TypeMap.php @@ -0,0 +1,190 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function array_any; +use function array_key_exists; +use function class_exists; +use function class_implements; +use function in_array; +use function interface_exists; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TypeMap +{ + /** + * @var array + */ + private array $mapping = []; + + /** + * @param class-string $subscriberInterface + * @param class-string $eventClass + * + * @throws EventAlreadyAssignedException + * @throws InvalidEventException + * @throws InvalidSubscriberException + * @throws SubscriberTypeAlreadyRegisteredException + * @throws UnknownEventException + * @throws UnknownSubscriberException + */ + public function addMapping(string $subscriberInterface, string $eventClass): void + { + $this->ensureSubscriberInterfaceExists($subscriberInterface); + $this->ensureSubscriberInterfaceExtendsInterface($subscriberInterface); + $this->ensureEventClassExists($eventClass); + $this->ensureEventClassImplementsEventInterface($eventClass); + $this->ensureSubscriberWasNotAlreadyRegistered($subscriberInterface); + $this->ensureEventWasNotAlreadyAssigned($eventClass); + + $this->mapping[$subscriberInterface] = $eventClass; + } + + public function isKnownSubscriberType(Subscriber $subscriber): bool + { + return array_any( + class_implements($subscriber), + fn (string $interface) => array_key_exists($interface, $this->mapping), + ); + } + + public function isKnownEventType(Event $event): bool + { + return in_array($event::class, $this->mapping, true); + } + + /** + * @throws MapError + * + * @return class-string + */ + public function map(Subscriber $subscriber): string + { + foreach (class_implements($subscriber) as $interface) { + if (array_key_exists($interface, $this->mapping)) { + return $this->mapping[$interface]; + } + } + + throw new MapError( + sprintf( + 'Subscriber "%s" does not implement a known interface', + $subscriber::class, + ), + ); + } + + /** + * @param class-string $subscriberInterface + * + * @throws UnknownSubscriberException + */ + private function ensureSubscriberInterfaceExists(string $subscriberInterface): void + { + if (!interface_exists($subscriberInterface)) { + throw new UnknownSubscriberException( + sprintf( + 'Subscriber "%s" does not exist or is not an interface', + $subscriberInterface, + ), + ); + } + } + + /** + * @param class-string $eventClass + * + * @throws UnknownEventException + */ + private function ensureEventClassExists(string $eventClass): void + { + if (!class_exists($eventClass)) { + throw new UnknownEventException( + sprintf( + 'Event class "%s" does not exist', + $eventClass, + ), + ); + } + } + + /** + * @param class-string $subscriberInterface + * + * @throws InvalidSubscriberException + */ + private function ensureSubscriberInterfaceExtendsInterface(string $subscriberInterface): void + { + if (!in_array(Subscriber::class, class_implements($subscriberInterface), true)) { + throw new InvalidSubscriberException( + sprintf( + 'Subscriber "%s" does not extend Subscriber interface', + $subscriberInterface, + ), + ); + } + } + + /** + * @param class-string $eventClass + * + * @throws InvalidEventException + */ + private function ensureEventClassImplementsEventInterface(string $eventClass): void + { + if (!in_array(Event::class, class_implements($eventClass), true)) { + throw new InvalidEventException( + sprintf( + 'Event "%s" does not implement Event interface', + $eventClass, + ), + ); + } + } + + /** + * @param class-string $subscriberInterface + * + * @throws SubscriberTypeAlreadyRegisteredException + */ + private function ensureSubscriberWasNotAlreadyRegistered(string $subscriberInterface): void + { + if (array_key_exists($subscriberInterface, $this->mapping)) { + throw new SubscriberTypeAlreadyRegisteredException( + sprintf( + 'Subscriber type "%s" already registered', + $subscriberInterface, + ), + ); + } + } + + /** + * @param class-string $eventClass + * + * @throws EventAlreadyAssignedException + */ + private function ensureEventWasNotAlreadyAssigned(string $eventClass): void + { + if (in_array($eventClass, $this->mapping, true)) { + throw new EventAlreadyAssignedException( + sprintf( + 'Event "%s" already assigned', + $eventClass, + ), + ); + } + } +} diff --git a/src/Event/Value/ClassMethod.php b/src/Event/Value/ClassMethod.php new file mode 100644 index 00000000000..2a94033a5db --- /dev/null +++ b/src/Event/Value/ClassMethod.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ClassMethod +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Event/Value/ComparisonFailure.php b/src/Event/Value/ComparisonFailure.php new file mode 100644 index 00000000000..c31f93e65cd --- /dev/null +++ b/src/Event/Value/ComparisonFailure.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonFailure +{ + private string $expected; + private string $actual; + private string $diff; + + public function __construct(string $expected, string $actual, string $diff) + { + $this->expected = $expected; + $this->actual = $actual; + $this->diff = $diff; + } + + public function expected(): string + { + return $this->expected; + } + + public function actual(): string + { + return $this->actual; + } + + public function diff(): string + { + return $this->diff; + } +} diff --git a/src/Event/Value/ComparisonFailureBuilder.php b/src/Event/Value/ComparisonFailureBuilder.php new file mode 100644 index 00000000000..53fe0d09aec --- /dev/null +++ b/src/Event/Value/ComparisonFailureBuilder.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_bool; +use function is_scalar; +use function print_r; +use PHPUnit\Framework\ExpectationFailedException; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonFailureBuilder +{ + public static function from(Throwable $t): ?ComparisonFailure + { + if (!$t instanceof ExpectationFailedException) { + return null; + } + + if ($t->getComparisonFailure() === null) { + return null; + } + + $expectedAsString = $t->getComparisonFailure()->getExpectedAsString(); + + if ($expectedAsString === '') { + $expectedAsString = self::mapScalarValueToString($t->getComparisonFailure()->getExpected()); + } + + $actualAsString = $t->getComparisonFailure()->getActualAsString(); + + if ($actualAsString === '') { + $actualAsString = self::mapScalarValueToString($t->getComparisonFailure()->getActual()); + } + + return new ComparisonFailure( + $expectedAsString, + $actualAsString, + $t->getComparisonFailure()->getDiff(), + ); + } + + private static function mapScalarValueToString(mixed $value): string + { + if ($value === null) { + return 'null'; + } + + if (is_bool($value)) { + return $value ? 'true' : 'false'; + } + + if (is_scalar($value)) { + return print_r($value, true); + } + + return ''; + } +} diff --git a/src/Event/Value/Runtime/OperatingSystem.php b/src/Event/Value/Runtime/OperatingSystem.php new file mode 100644 index 00000000000..508d809f103 --- /dev/null +++ b/src/Event/Value/Runtime/OperatingSystem.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_OS; +use const PHP_OS_FAMILY; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class OperatingSystem +{ + private string $operatingSystem; + private string $operatingSystemFamily; + + public function __construct() + { + $this->operatingSystem = PHP_OS; + $this->operatingSystemFamily = PHP_OS_FAMILY; + } + + public function operatingSystem(): string + { + return $this->operatingSystem; + } + + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} diff --git a/src/Event/Value/Runtime/PHP.php b/src/Event/Value/Runtime/PHP.php new file mode 100644 index 00000000000..46004f98c65 --- /dev/null +++ b/src/Event/Value/Runtime/PHP.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_EXTRA_VERSION; +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; +use const PHP_RELEASE_VERSION; +use const PHP_SAPI; +use const PHP_VERSION; +use const PHP_VERSION_ID; +use function array_merge; +use function get_loaded_extensions; +use function sort; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PHP +{ + private string $version; + private int $versionId; + private int $majorVersion; + private int $minorVersion; + private int $releaseVersion; + private string $extraVersion; + private string $sapi; + + /** + * @var list + */ + private array $extensions; + + public function __construct() + { + $this->version = PHP_VERSION; + $this->versionId = PHP_VERSION_ID; + $this->majorVersion = PHP_MAJOR_VERSION; + $this->minorVersion = PHP_MINOR_VERSION; + $this->releaseVersion = PHP_RELEASE_VERSION; + $this->extraVersion = PHP_EXTRA_VERSION; + $this->sapi = PHP_SAPI; + + $extensions = array_merge( + get_loaded_extensions(true), + get_loaded_extensions(), + ); + + sort($extensions); + + $this->extensions = $extensions; + } + + public function version(): string + { + return $this->version; + } + + public function sapi(): string + { + return $this->sapi; + } + + public function majorVersion(): int + { + return $this->majorVersion; + } + + public function minorVersion(): int + { + return $this->minorVersion; + } + + public function releaseVersion(): int + { + return $this->releaseVersion; + } + + public function extraVersion(): string + { + return $this->extraVersion; + } + + public function versionId(): int + { + return $this->versionId; + } + + /** + * @return list + */ + public function extensions(): array + { + return $this->extensions; + } +} diff --git a/src/Event/Value/Runtime/PHPUnit.php b/src/Event/Value/Runtime/PHPUnit.php new file mode 100644 index 00000000000..7f85133d2cc --- /dev/null +++ b/src/Event/Value/Runtime/PHPUnit.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use PHPUnit\Runner\Version; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PHPUnit +{ + private string $versionId; + private string $releaseSeries; + + public function __construct() + { + $this->versionId = Version::id(); + $this->releaseSeries = Version::series(); + } + + public function versionId(): string + { + return $this->versionId; + } + + public function releaseSeries(): string + { + return $this->releaseSeries; + } +} diff --git a/src/Event/Value/Runtime/Runtime.php b/src/Event/Value/Runtime/Runtime.php new file mode 100644 index 00000000000..552ec98878f --- /dev/null +++ b/src/Event/Value/Runtime/Runtime.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use function sprintf; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Runtime +{ + private OperatingSystem $operatingSystem; + private PHP $php; + private PHPUnit $phpunit; + + public function __construct() + { + $this->operatingSystem = new OperatingSystem; + $this->php = new PHP; + $this->phpunit = new PHPUnit; + } + + public function asString(): string + { + $php = $this->php(); + + return sprintf( + 'PHPUnit %s using PHP %s (%s) on %s', + $this->phpunit()->versionId(), + $php->version(), + $php->sapi(), + $this->operatingSystem()->operatingSystem(), + ); + } + + public function operatingSystem(): OperatingSystem + { + return $this->operatingSystem; + } + + public function php(): PHP + { + return $this->php; + } + + public function phpunit(): PHPUnit + { + return $this->phpunit; + } +} diff --git a/src/Event/Value/Telemetry/Duration.php b/src/Event/Value/Telemetry/Duration.php new file mode 100644 index 00000000000..230150a159b --- /dev/null +++ b/src/Event/Value/Telemetry/Duration.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function floor; +use function sprintf; +use PHPUnit\Event\InvalidArgumentException; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Duration +{ + private int $seconds; + private int $nanoseconds; + + /** + * @throws InvalidArgumentException + */ + public static function fromSecondsAndNanoseconds(int $seconds, int $nanoseconds): self + { + return new self( + $seconds, + $nanoseconds, + ); + } + + /** + * @throws InvalidArgumentException + */ + private function __construct(int $seconds, int $nanoseconds) + { + $this->ensureNotNegative($seconds, 'seconds'); + $this->ensureNotNegative($nanoseconds, 'nanoseconds'); + $this->ensureNanoSecondsInRange($nanoseconds); + + $this->seconds = $seconds; + $this->nanoseconds = $nanoseconds; + } + + public function seconds(): int + { + return $this->seconds; + } + + public function nanoseconds(): int + { + return $this->nanoseconds; + } + + public function asFloat(): float + { + return $this->seconds() + ($this->nanoseconds() / 1000000000); + } + + public function asString(): string + { + $seconds = $this->seconds(); + $minutes = 0; + $hours = 0; + + if ($seconds > 60 * 60) { + $hours = floor($seconds / 60 / 60); + $seconds -= ($hours * 60 * 60); + } + + if ($seconds > 60) { + $minutes = floor($seconds / 60); + $seconds -= ($minutes * 60); + } + + return sprintf( + '%02d:%02d:%02d.%09d', + $hours, + $minutes, + $seconds, + $this->nanoseconds(), + ); + } + + public function equals(self $other): bool + { + return $this->seconds === $other->seconds && + $this->nanoseconds === $other->nanoseconds; + } + + public function isLessThan(self $other): bool + { + if ($this->seconds < $other->seconds) { + return true; + } + + if ($this->seconds > $other->seconds) { + return false; + } + + return $this->nanoseconds < $other->nanoseconds; + } + + public function isGreaterThan(self $other): bool + { + if ($this->seconds > $other->seconds) { + return true; + } + + if ($this->seconds < $other->seconds) { + return false; + } + + return $this->nanoseconds > $other->nanoseconds; + } + + /** + * @throws InvalidArgumentException + */ + private function ensureNotNegative(int $value, string $type): void + { + if ($value < 0) { + throw new InvalidArgumentException( + sprintf( + 'Value for %s must not be negative.', + $type, + ), + ); + } + } + + /** + * @throws InvalidArgumentException + */ + private function ensureNanoSecondsInRange(int $nanoseconds): void + { + if ($nanoseconds > 999999999) { + throw new InvalidArgumentException( + 'Value for nanoseconds must not be greater than 999999999.', + ); + } + } +} diff --git a/src/Event/Value/Telemetry/GarbageCollectorStatus.php b/src/Event/Value/Telemetry/GarbageCollectorStatus.php new file mode 100644 index 00000000000..f8bb77a74ec --- /dev/null +++ b/src/Event/Value/Telemetry/GarbageCollectorStatus.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GarbageCollectorStatus +{ + private int $runs; + private int $collected; + private int $threshold; + private int $roots; + private float $applicationTime; + private float $collectorTime; + private float $destructorTime; + private float $freeTime; + private bool $running; + private bool $protected; + private bool $full; + private int $bufferSize; + + public function __construct(int $runs, int $collected, int $threshold, int $roots, float $applicationTime, float $collectorTime, float $destructorTime, float $freeTime, bool $running, bool $protected, bool $full, int $bufferSize) + { + $this->runs = $runs; + $this->collected = $collected; + $this->threshold = $threshold; + $this->roots = $roots; + $this->applicationTime = $applicationTime; + $this->collectorTime = $collectorTime; + $this->destructorTime = $destructorTime; + $this->freeTime = $freeTime; + $this->running = $running; + $this->protected = $protected; + $this->full = $full; + $this->bufferSize = $bufferSize; + } + + public function runs(): int + { + return $this->runs; + } + + public function collected(): int + { + return $this->collected; + } + + public function threshold(): int + { + return $this->threshold; + } + + public function roots(): int + { + return $this->roots; + } + + public function applicationTime(): float + { + return $this->applicationTime; + } + + public function collectorTime(): float + { + return $this->collectorTime; + } + + public function destructorTime(): float + { + return $this->destructorTime; + } + + public function freeTime(): float + { + return $this->freeTime; + } + + public function isRunning(): bool + { + return $this->running; + } + + public function isProtected(): bool + { + return $this->protected; + } + + public function isFull(): bool + { + return $this->full; + } + + public function bufferSize(): int + { + return $this->bufferSize; + } +} diff --git a/src/Event/Value/Telemetry/GarbageCollectorStatusProvider.php b/src/Event/Value/Telemetry/GarbageCollectorStatusProvider.php new file mode 100644 index 00000000000..09bede2e539 --- /dev/null +++ b/src/Event/Value/Telemetry/GarbageCollectorStatusProvider.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface GarbageCollectorStatusProvider +{ + public function status(): GarbageCollectorStatus; +} diff --git a/src/Event/Value/Telemetry/HRTime.php b/src/Event/Value/Telemetry/HRTime.php new file mode 100644 index 00000000000..8a7b97ebd04 --- /dev/null +++ b/src/Event/Value/Telemetry/HRTime.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function sprintf; +use PHPUnit\Event\InvalidArgumentException; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HRTime +{ + private int $seconds; + private int $nanoseconds; + + /** + * @throws InvalidArgumentException + */ + public static function fromSecondsAndNanoseconds(int $seconds, int $nanoseconds): self + { + return new self( + $seconds, + $nanoseconds, + ); + } + + /** + * @throws InvalidArgumentException + */ + private function __construct(int $seconds, int $nanoseconds) + { + $this->ensureNotNegative($seconds, 'seconds'); + $this->ensureNotNegative($nanoseconds, 'nanoseconds'); + $this->ensureNanoSecondsInRange($nanoseconds); + + $this->seconds = $seconds; + $this->nanoseconds = $nanoseconds; + } + + public function seconds(): int + { + return $this->seconds; + } + + public function nanoseconds(): int + { + return $this->nanoseconds; + } + + public function duration(self $start): Duration + { + $seconds = $this->seconds - $start->seconds(); + $nanoseconds = $this->nanoseconds - $start->nanoseconds(); + + if ($nanoseconds < 0) { + $seconds--; + + $nanoseconds += 1000000000; + } + + if ($seconds < 0) { + return Duration::fromSecondsAndNanoseconds(0, 0); + } + + return Duration::fromSecondsAndNanoseconds( + $seconds, + $nanoseconds, + ); + } + + /** + * @throws InvalidArgumentException + */ + private function ensureNotNegative(int $value, string $type): void + { + if ($value < 0) { + throw new InvalidArgumentException( + sprintf( + 'Value for %s must not be negative.', + $type, + ), + ); + } + } + + /** + * @throws InvalidArgumentException + */ + private function ensureNanoSecondsInRange(int $nanoseconds): void + { + if ($nanoseconds > 999999999) { + throw new InvalidArgumentException( + 'Value for nanoseconds must not be greater than 999999999.', + ); + } + } +} diff --git a/src/Event/Value/Telemetry/Info.php b/src/Event/Value/Telemetry/Info.php new file mode 100644 index 00000000000..a0d0a99f169 --- /dev/null +++ b/src/Event/Value/Telemetry/Info.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function sprintf; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Info +{ + private Snapshot $current; + private Duration $durationSinceStart; + private MemoryUsage $memorySinceStart; + private Duration $durationSincePrevious; + private MemoryUsage $memorySincePrevious; + + public function __construct(Snapshot $current, Duration $durationSinceStart, MemoryUsage $memorySinceStart, Duration $durationSincePrevious, MemoryUsage $memorySincePrevious) + { + $this->current = $current; + $this->durationSinceStart = $durationSinceStart; + $this->memorySinceStart = $memorySinceStart; + $this->durationSincePrevious = $durationSincePrevious; + $this->memorySincePrevious = $memorySincePrevious; + } + + public function time(): HRTime + { + return $this->current->time(); + } + + public function memoryUsage(): MemoryUsage + { + return $this->current->memoryUsage(); + } + + public function peakMemoryUsage(): MemoryUsage + { + return $this->current->peakMemoryUsage(); + } + + public function durationSinceStart(): Duration + { + return $this->durationSinceStart; + } + + public function memoryUsageSinceStart(): MemoryUsage + { + return $this->memorySinceStart; + } + + public function durationSincePrevious(): Duration + { + return $this->durationSincePrevious; + } + + public function memoryUsageSincePrevious(): MemoryUsage + { + return $this->memorySincePrevious; + } + + public function garbageCollectorStatus(): GarbageCollectorStatus + { + return $this->current->garbageCollectorStatus(); + } + + public function asString(): string + { + return sprintf( + '[%s / %s] [%d bytes]', + $this->durationSinceStart()->asString(), + $this->durationSincePrevious()->asString(), + $this->peakMemoryUsage()->bytes(), + ); + } +} diff --git a/src/Event/Value/Telemetry/MemoryMeter.php b/src/Event/Value/Telemetry/MemoryMeter.php new file mode 100644 index 00000000000..4d116ff3ef3 --- /dev/null +++ b/src/Event/Value/Telemetry/MemoryMeter.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface MemoryMeter +{ + public function memoryUsage(): MemoryUsage; + + public function peakMemoryUsage(): MemoryUsage; +} diff --git a/src/Event/Value/Telemetry/MemoryUsage.php b/src/Event/Value/Telemetry/MemoryUsage.php new file mode 100644 index 00000000000..8ace32ea0bf --- /dev/null +++ b/src/Event/Value/Telemetry/MemoryUsage.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MemoryUsage +{ + private int $bytes; + + public static function fromBytes(int $bytes): self + { + return new self($bytes); + } + + private function __construct(int $bytes) + { + $this->bytes = $bytes; + } + + public function bytes(): int + { + return $this->bytes; + } + + public function diff(self $other): self + { + return self::fromBytes($this->bytes - $other->bytes); + } +} diff --git a/src/Event/Value/Telemetry/Snapshot.php b/src/Event/Value/Telemetry/Snapshot.php new file mode 100644 index 00000000000..0f00f5d8054 --- /dev/null +++ b/src/Event/Value/Telemetry/Snapshot.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Snapshot +{ + private HRTime $time; + private MemoryUsage $memoryUsage; + private MemoryUsage $peakMemoryUsage; + private GarbageCollectorStatus $garbageCollectorStatus; + + public function __construct(HRTime $time, MemoryUsage $memoryUsage, MemoryUsage $peakMemoryUsage, GarbageCollectorStatus $garbageCollectorStatus) + { + $this->time = $time; + $this->memoryUsage = $memoryUsage; + $this->peakMemoryUsage = $peakMemoryUsage; + $this->garbageCollectorStatus = $garbageCollectorStatus; + } + + public function time(): HRTime + { + return $this->time; + } + + public function memoryUsage(): MemoryUsage + { + return $this->memoryUsage; + } + + public function peakMemoryUsage(): MemoryUsage + { + return $this->peakMemoryUsage; + } + + public function garbageCollectorStatus(): GarbageCollectorStatus + { + return $this->garbageCollectorStatus; + } +} diff --git a/src/Event/Value/Telemetry/StopWatch.php b/src/Event/Value/Telemetry/StopWatch.php new file mode 100644 index 00000000000..07ce5227faa --- /dev/null +++ b/src/Event/Value/Telemetry/StopWatch.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface StopWatch +{ + public function current(): HRTime; +} diff --git a/src/Event/Value/Telemetry/System.php b/src/Event/Value/Telemetry/System.php new file mode 100644 index 00000000000..0a178363e55 --- /dev/null +++ b/src/Event/Value/Telemetry/System.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class System +{ + private StopWatch $stopWatch; + private MemoryMeter $memoryMeter; + private GarbageCollectorStatusProvider $garbageCollectorStatusProvider; + + public function __construct(StopWatch $stopWatch, MemoryMeter $memoryMeter, GarbageCollectorStatusProvider $garbageCollectorStatusProvider) + { + $this->stopWatch = $stopWatch; + $this->memoryMeter = $memoryMeter; + $this->garbageCollectorStatusProvider = $garbageCollectorStatusProvider; + } + + public function snapshot(): Snapshot + { + return new Snapshot( + $this->stopWatch->current(), + $this->memoryMeter->memoryUsage(), + $this->memoryMeter->peakMemoryUsage(), + $this->garbageCollectorStatusProvider->status(), + ); + } +} diff --git a/src/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.php b/src/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.php new file mode 100644 index 00000000000..3f33d690d0e --- /dev/null +++ b/src/Event/Value/Telemetry/SystemGarbageCollectorStatusProvider.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function gc_status; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemGarbageCollectorStatusProvider implements GarbageCollectorStatusProvider +{ + public function status(): GarbageCollectorStatus + { + $status = gc_status(); + + return new GarbageCollectorStatus( + $status['runs'], + $status['collected'], + $status['threshold'], + $status['roots'], + $status['application_time'], + $status['collector_time'], + $status['destructor_time'], + $status['free_time'], + $status['running'], + $status['protected'], + $status['full'], + $status['buffer_size'], + ); + } +} diff --git a/src/Event/Value/Telemetry/SystemMemoryMeter.php b/src/Event/Value/Telemetry/SystemMemoryMeter.php new file mode 100644 index 00000000000..16d895a949b --- /dev/null +++ b/src/Event/Value/Telemetry/SystemMemoryMeter.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function memory_get_peak_usage; +use function memory_get_usage; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemMemoryMeter implements MemoryMeter +{ + public function memoryUsage(): MemoryUsage + { + return MemoryUsage::fromBytes(memory_get_usage()); + } + + public function peakMemoryUsage(): MemoryUsage + { + return MemoryUsage::fromBytes(memory_get_peak_usage()); + } +} diff --git a/src/Event/Value/Telemetry/SystemStopWatch.php b/src/Event/Value/Telemetry/SystemStopWatch.php new file mode 100644 index 00000000000..a57c1032407 --- /dev/null +++ b/src/Event/Value/Telemetry/SystemStopWatch.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Event\InvalidArgumentException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SystemStopWatch implements StopWatch +{ + /** + * @throws InvalidArgumentException + */ + public function current(): HRTime + { + return HRTime::fromSecondsAndNanoseconds(...hrtime()); + } +} diff --git a/src/Event/Value/Telemetry/SystemStopWatchWithOffset.php b/src/Event/Value/Telemetry/SystemStopWatchWithOffset.php new file mode 100644 index 00000000000..d27fd98c14b --- /dev/null +++ b/src/Event/Value/Telemetry/SystemStopWatchWithOffset.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Event\InvalidArgumentException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class SystemStopWatchWithOffset implements StopWatch +{ + private ?HRTime $offset; + + public function __construct(HRTime $offset) + { + $this->offset = $offset; + } + + /** + * @throws InvalidArgumentException + */ + public function current(): HRTime + { + if ($this->offset !== null) { + $offset = $this->offset; + + $this->offset = null; + + return $offset; + } + + return HRTime::fromSecondsAndNanoseconds(...hrtime()); + } +} diff --git a/src/Event/Value/Test/Issue/DirectTrigger.php b/src/Event/Value/Test/Issue/DirectTrigger.php new file mode 100644 index 00000000000..bbb3c66a890 --- /dev/null +++ b/src/Event/Value/Test/Issue/DirectTrigger.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class DirectTrigger extends IssueTrigger +{ + /** + * Your own code triggers an issue in third-party code. + */ + public function isDirect(): true + { + return true; + } + + public function asString(): string + { + return 'issue triggered by first-party code calling into third-party code'; + } +} diff --git a/src/Event/Value/Test/Issue/IndirectTrigger.php b/src/Event/Value/Test/Issue/IndirectTrigger.php new file mode 100644 index 00000000000..81f76b45e9a --- /dev/null +++ b/src/Event/Value/Test/Issue/IndirectTrigger.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IndirectTrigger extends IssueTrigger +{ + /** + * Third-party code triggers an issue either in your own code or in third-party code. + */ + public function isIndirect(): true + { + return true; + } + + public function asString(): string + { + return 'issue triggered by third-party code'; + } +} diff --git a/src/Event/Value/Test/Issue/IssueTrigger.php b/src/Event/Value/Test/Issue/IssueTrigger.php new file mode 100644 index 00000000000..93e42c72950 --- /dev/null +++ b/src/Event/Value/Test/Issue/IssueTrigger.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class IssueTrigger +{ + public static function test(): TestTrigger + { + return new TestTrigger; + } + + public static function self(): SelfTrigger + { + return new SelfTrigger; + } + + public static function direct(): DirectTrigger + { + return new DirectTrigger; + } + + public static function indirect(): IndirectTrigger + { + return new IndirectTrigger; + } + + public static function unknown(): UnknownTrigger + { + return new UnknownTrigger; + } + + final private function __construct() + { + } + + /** + * Your test code triggers an issue. + * + * @phpstan-assert-if-true TestTrigger $this + */ + public function isTest(): bool + { + return false; + } + + /** + * Your own code triggers an issue in your own code. + * + * @phpstan-assert-if-true SelfTrigger $this + */ + public function isSelf(): bool + { + return false; + } + + /** + * Your own code triggers an issue in third-party code. + * + * @phpstan-assert-if-true DirectTrigger $this + */ + public function isDirect(): bool + { + return false; + } + + /** + * Third-party code triggers an issue either in your own code or in third-party code. + * + * @phpstan-assert-if-true IndirectTrigger $this + */ + public function isIndirect(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UnknownTrigger $this + */ + public function isUnknown(): bool + { + return false; + } + + abstract public function asString(): string; +} diff --git a/src/Event/Value/Test/Issue/SelfTrigger.php b/src/Event/Value/Test/Issue/SelfTrigger.php new file mode 100644 index 00000000000..e569e72f578 --- /dev/null +++ b/src/Event/Value/Test/Issue/SelfTrigger.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class SelfTrigger extends IssueTrigger +{ + /** + * Your own code triggers an issue in your own code. + */ + public function isSelf(): true + { + return true; + } + + public function asString(): string + { + return 'issue triggered by first-party code calling into first-party code'; + } +} diff --git a/src/Event/Value/Test/Issue/TestTrigger.php b/src/Event/Value/Test/Issue/TestTrigger.php new file mode 100644 index 00000000000..4768baca6bd --- /dev/null +++ b/src/Event/Value/Test/Issue/TestTrigger.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestTrigger extends IssueTrigger +{ + /** + * Your test code triggers an issue. + */ + public function isTest(): true + { + return true; + } + + public function asString(): string + { + return 'issue triggered by test code'; + } +} diff --git a/src/Event/Value/Test/Issue/UnknownTrigger.php b/src/Event/Value/Test/Issue/UnknownTrigger.php new file mode 100644 index 00000000000..61f81148929 --- /dev/null +++ b/src/Event/Value/Test/Issue/UnknownTrigger.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownTrigger extends IssueTrigger +{ + public function isUnknown(): true + { + return true; + } + + public function asString(): string + { + return 'unknown if issue was triggered in first-party code or third-party code'; + } +} diff --git a/src/Event/Value/Test/Phpt.php b/src/Event/Value/Test/Phpt.php new file mode 100644 index 00000000000..65a3aec8268 --- /dev/null +++ b/src/Event/Value/Test/Phpt.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Phpt extends Test +{ + public function isPhpt(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function id(): string + { + return $this->file(); + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->file(); + } +} diff --git a/src/Event/Value/Test/Test.php b/src/Event/Value/Test/Test.php new file mode 100644 index 00000000000..43ed73eb7b6 --- /dev/null +++ b/src/Event/Value/Test/Test.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Test +{ + /** + * @var non-empty-string + */ + private string $file; + + /** + * @param non-empty-string $file + */ + public function __construct(string $file) + { + $this->file = $file; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @phpstan-assert-if-true TestMethod $this + */ + public function isTestMethod(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Phpt $this + */ + public function isPhpt(): bool + { + return false; + } + + /** + * @return non-empty-string + */ + abstract public function id(): string; + + /** + * @return non-empty-string + */ + abstract public function name(): string; +} diff --git a/src/Event/Value/Test/TestCollection.php b/src/Event/Value/Test/TestCollection.php new file mode 100644 index 00000000000..1924b64b614 --- /dev/null +++ b/src/Event/Value/Test/TestCollection.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $tests; + + /** + * @param list $tests + */ + public static function fromArray(array $tests): self + { + return new self(...$tests); + } + + private function __construct(Test ...$tests) + { + $this->tests = $tests; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->tests; + } + + public function count(): int + { + return count($this->tests); + } + + public function getIterator(): TestCollectionIterator + { + return new TestCollectionIterator($this); + } +} diff --git a/src/Event/Value/Test/TestCollectionIterator.php b/src/Event/Value/Test/TestCollectionIterator.php new file mode 100644 index 00000000000..7c96f3409e4 --- /dev/null +++ b/src/Event/Value/Test/TestCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function count; +use Iterator; + +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $tests; + private int $position = 0; + + public function __construct(TestCollection $tests) + { + $this->tests = $tests->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->tests); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Test + { + return $this->tests[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/Event/Value/Test/TestData/DataFromDataProvider.php b/src/Event/Value/Test/TestData/DataFromDataProvider.php new file mode 100644 index 00000000000..981fd9e4f65 --- /dev/null +++ b/src/Event/Value/Test/TestData/DataFromDataProvider.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataFromDataProvider extends TestData +{ + private int|string $dataSetName; + private string $dataAsStringForResultOutput; + + public static function from(int|string $dataSetName, string $data, string $dataAsStringForResultOutput): self + { + return new self($dataSetName, $data, $dataAsStringForResultOutput); + } + + protected function __construct(int|string $dataSetName, string $data, string $dataAsStringForResultOutput) + { + $this->dataSetName = $dataSetName; + $this->dataAsStringForResultOutput = $dataAsStringForResultOutput; + + parent::__construct($data); + } + + public function dataSetName(): int|string + { + return $this->dataSetName; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function dataAsStringForResultOutput(): string + { + return $this->dataAsStringForResultOutput; + } + + public function isFromDataProvider(): true + { + return true; + } +} diff --git a/src/Event/Value/Test/TestData/DataFromTestDependency.php b/src/Event/Value/Test/TestData/DataFromTestDependency.php new file mode 100644 index 00000000000..9fbf17ebf43 --- /dev/null +++ b/src/Event/Value/Test/TestData/DataFromTestDependency.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataFromTestDependency extends TestData +{ + public static function from(string $data): self + { + return new self($data); + } + + public function isFromTestDependency(): true + { + return true; + } +} diff --git a/src/Event/Value/Test/TestData/TestData.php b/src/Event/Value/Test/TestData/TestData.php new file mode 100644 index 00000000000..893444806c2 --- /dev/null +++ b/src/Event/Value/Test/TestData/TestData.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestData +{ + private string $data; + + protected function __construct(string $data) + { + $this->data = $data; + } + + public function data(): string + { + return $this->data; + } + + /** + * @phpstan-assert-if-true DataFromDataProvider $this + */ + public function isFromDataProvider(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DataFromTestDependency $this + */ + public function isFromTestDependency(): bool + { + return false; + } +} diff --git a/src/Event/Value/Test/TestData/TestDataCollection.php b/src/Event/Value/Test/TestData/TestDataCollection.php new file mode 100644 index 00000000000..460f0c0c59b --- /dev/null +++ b/src/Event/Value/Test/TestData/TestDataCollection.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDataCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $data; + private ?DataFromDataProvider $fromDataProvider; + + /** + * @param list $data + */ + public static function fromArray(array $data): self + { + return new self(...$data); + } + + private function __construct(TestData ...$data) + { + $fromDataProvider = null; + + foreach ($data as $_data) { + if ($_data->isFromDataProvider()) { + $fromDataProvider = $_data; + } + } + + $this->data = $data; + $this->fromDataProvider = $fromDataProvider; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->data; + } + + public function count(): int + { + return count($this->data); + } + + /** + * @phpstan-assert-if-true !null $this->fromDataProvider + */ + public function hasDataFromDataProvider(): bool + { + return $this->fromDataProvider !== null; + } + + /** + * @throws NoDataSetFromDataProviderException + */ + public function dataFromDataProvider(): DataFromDataProvider + { + if (!$this->hasDataFromDataProvider()) { + throw new NoDataSetFromDataProviderException; + } + + return $this->fromDataProvider; + } + + public function getIterator(): TestDataCollectionIterator + { + return new TestDataCollectionIterator($this); + } +} diff --git a/src/Event/Value/Test/TestData/TestDataCollectionIterator.php b/src/Event/Value/Test/TestData/TestDataCollectionIterator.php new file mode 100644 index 00000000000..aebed66ca17 --- /dev/null +++ b/src/Event/Value/Test/TestData/TestDataCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use function count; +use Iterator; + +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestDataCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $data; + private int $position = 0; + + public function __construct(TestDataCollection $data) + { + $this->data = $data->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->data); + } + + public function key(): int + { + return $this->position; + } + + public function current(): TestData + { + return $this->data[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/Event/Value/Test/TestDox.php b/src/Event/Value/Test/TestDox.php new file mode 100644 index 00000000000..53604dbfc65 --- /dev/null +++ b/src/Event/Value/Test/TestDox.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDox +{ + private string $prettifiedClassName; + private string $prettifiedMethodName; + private string $prettifiedAndColorizedMethodName; + + public function __construct(string $prettifiedClassName, string $prettifiedMethodName, string $prettifiedAndColorizedMethodName) + { + $this->prettifiedClassName = $prettifiedClassName; + $this->prettifiedMethodName = $prettifiedMethodName; + $this->prettifiedAndColorizedMethodName = $prettifiedAndColorizedMethodName; + } + + public function prettifiedClassName(): string + { + return $this->prettifiedClassName; + } + + public function prettifiedMethodName(bool $colorize = false): string + { + if ($colorize) { + return $this->prettifiedAndColorizedMethodName; + } + + return $this->prettifiedMethodName; + } +} diff --git a/src/Event/Value/Test/TestDoxBuilder.php b/src/Event/Value/Test/TestDoxBuilder.php new file mode 100644 index 00000000000..532dde00378 --- /dev/null +++ b/src/Event/Value/Test/TestDoxBuilder.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Framework\TestCase; +use PHPUnit\Logging\TestDox\NamePrettifier; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDoxBuilder +{ + private static ?NamePrettifier $namePrettifier = null; + + public static function fromTestCase(TestCase $testCase): TestDox + { + $prettifier = self::namePrettifier(); + + return new TestDox( + $prettifier->prettifyTestClassName($testCase::class), + $prettifier->prettifyTestCase($testCase, false), + $prettifier->prettifyTestCase($testCase, true), + ); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function fromClassNameAndMethodName(string $className, string $methodName): TestDox + { + $prettifier = self::namePrettifier(); + + $prettifiedMethodName = $prettifier->prettifyTestMethodName($methodName); + + return new TestDox( + $prettifier->prettifyTestClassName($className), + $prettifiedMethodName, + $prettifiedMethodName, + ); + } + + private static function namePrettifier(): NamePrettifier + { + if (self::$namePrettifier === null) { + self::$namePrettifier = new NamePrettifier; + } + + return self::$namePrettifier; + } +} diff --git a/src/Event/Value/Test/TestMethod.php b/src/Event/Value/Test/TestMethod.php new file mode 100644 index 00000000000..4c972645436 --- /dev/null +++ b/src/Event/Value/Test/TestMethod.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_int; +use function sprintf; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Metadata\MetadataCollection; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMethod extends Test +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @var non-negative-int + */ + private int $line; + private TestDox $testDox; + private MetadataCollection $metadata; + private TestDataCollection $testData; + + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param non-empty-string $file + * @param non-negative-int $line + */ + public function __construct(string $className, string $methodName, string $file, int $line, TestDox $testDox, MetadataCollection $metadata, TestDataCollection $testData) + { + parent::__construct($file); + + $this->className = $className; + $this->methodName = $methodName; + $this->line = $line; + $this->testDox = $testDox; + $this->metadata = $metadata; + $this->testData = $testData; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + /** + * @return non-negative-int + */ + public function line(): int + { + return $this->line; + } + + public function testDox(): TestDox + { + return $this->testDox; + } + + public function metadata(): MetadataCollection + { + return $this->metadata; + } + + public function testData(): TestDataCollection + { + return $this->testData; + } + + public function isTestMethod(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function id(): string + { + $buffer = $this->className . '::' . $this->methodName; + + if ($this->testData()->hasDataFromDataProvider()) { + $buffer .= '#' . $this->testData->dataFromDataProvider()->dataSetName(); + } + + return $buffer; + } + + /** + * @return non-empty-string + */ + public function nameWithClass(): string + { + return $this->className . '::' . $this->name(); + } + + /** + * @return non-empty-string + */ + public function name(): string + { + if (!$this->testData->hasDataFromDataProvider()) { + return $this->methodName; + } + + $dataSetName = $this->testData->dataFromDataProvider()->dataSetName(); + + if (is_int($dataSetName)) { + $dataSetName = sprintf( + ' with data set #%d', + $dataSetName, + ); + } else { + $dataSetName = sprintf( + ' with data set "%s"', + $dataSetName, + ); + } + + return $this->methodName . $dataSetName; + } +} diff --git a/src/Event/Value/Test/TestMethodBuilder.php b/src/Event/Value/Test/TestMethodBuilder.php new file mode 100644 index 00000000000..dc1a32ef8ab --- /dev/null +++ b/src/Event/Value/Test/TestMethodBuilder.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function is_numeric; +use PHPUnit\Event\TestData\DataFromDataProvider; +use PHPUnit\Event\TestData\DataFromTestDependency; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Reflection; +use PHPUnit\Util\Test as TestUtil; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMethodBuilder +{ + public static function fromTestCase(TestCase $testCase, bool $useTestCaseForTestDox = true): TestMethod + { + $methodName = $testCase->name(); + $location = Reflection::sourceLocationFor($testCase::class, $methodName); + + if ($useTestCaseForTestDox) { + $testDox = TestDoxBuilder::fromTestCase($testCase); + } else { + $testDox = TestDoxBuilder::fromClassNameAndMethodName($testCase::class, $testCase->name()); + } + + return new TestMethod( + $testCase::class, + $methodName, + $location['file'], + $location['line'], + $testDox, + MetadataRegistry::parser()->forClassAndMethod($testCase::class, $methodName), + self::dataFor($testCase), + ); + } + + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public static function fromCallStack(): TestMethod + { + return TestUtil::currentTestCase()->valueObjectForEvents(); + } + + private static function dataFor(TestCase $testCase): TestDataCollection + { + $testData = []; + + if ($testCase->usesDataProvider()) { + $dataSetName = $testCase->dataName(); + + if (is_numeric($dataSetName)) { + $dataSetName = (int) $dataSetName; + } + + $testData[] = DataFromDataProvider::from( + $dataSetName, + Exporter::shortenedRecursiveExport($testCase->providedData()), + $testCase->dataSetAsStringWithData(), + ); + } + + if ($testCase->hasDependencyInput()) { + $testData[] = DataFromTestDependency::from( + Exporter::shortenedRecursiveExport($testCase->dependencyInput()), + ); + } + + return TestDataCollection::fromArray($testData); + } +} diff --git a/src/Event/Value/TestSuite/TestSuite.php b/src/Event/Value/TestSuite/TestSuite.php new file mode 100644 index 00000000000..783de57bd24 --- /dev/null +++ b/src/Event/Value/TestSuite/TestSuite.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestSuite +{ + /** + * @var non-empty-string + */ + private string $name; + private int $count; + private TestCollection $tests; + + /** + * @param non-empty-string $name + */ + public function __construct(string $name, int $size, TestCollection $tests) + { + $this->name = $name; + $this->count = $size; + $this->tests = $tests; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + + public function count(): int + { + return $this->count; + } + + public function tests(): TestCollection + { + return $this->tests; + } + + /** + * @phpstan-assert-if-true TestSuiteWithName $this + */ + public function isWithName(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true TestSuiteForTestClass $this + */ + public function isForTestClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true TestSuiteForTestMethodWithDataProvider $this + */ + public function isForTestMethodWithDataProvider(): bool + { + return false; + } +} diff --git a/src/Event/Value/TestSuite/TestSuiteBuilder.php b/src/Event/Value/TestSuite/TestSuiteBuilder.php new file mode 100644 index 00000000000..3192636baa9 --- /dev/null +++ b/src/Event/Value/TestSuite/TestSuiteBuilder.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use function assert; +use function class_exists; +use function count; +use function explode; +use function method_exists; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestCollection; +use PHPUnit\Event\RuntimeException; +use PHPUnit\Framework\DataProviderTestSuite; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite as FrameworkTestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBuilder +{ + /** + * @throws RuntimeException + */ + public static function from(FrameworkTestSuite $testSuite): TestSuite + { + $tests = []; + + self::process($testSuite, $tests); + + if ($testSuite instanceof DataProviderTestSuite) { + assert(count(explode('::', $testSuite->name())) === 2); + [$className, $methodName] = explode('::', $testSuite->name()); + + assert(class_exists($className)); + assert($methodName !== '' && method_exists($className, $methodName)); + + $reflector = new ReflectionMethod($className, $methodName); + + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + + assert($file !== false); + assert($line !== false); + + return new TestSuiteForTestMethodWithDataProvider( + $testSuite->name(), + $testSuite->count(), + TestCollection::fromArray($tests), + $className, + $methodName, + $file, + $line, + ); + } + + if ($testSuite->isForTestClass()) { + $testClassName = $testSuite->name(); + + assert(class_exists($testClassName)); + + $reflector = new ReflectionClass($testClassName); + + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + + assert($file !== false); + assert($line !== false); + + return new TestSuiteForTestClass( + $testClassName, + $testSuite->count(), + TestCollection::fromArray($tests), + $file, + $line, + ); + } + + return new TestSuiteWithName( + $testSuite->name(), + $testSuite->count(), + TestCollection::fromArray($tests), + ); + } + + /** + * @param list $tests + */ + private static function process(FrameworkTestSuite $testSuite, array &$tests): void + { + foreach ($testSuite->getIterator() as $test) { + if ($test instanceof FrameworkTestSuite) { + self::process($test, $tests); + + continue; + } + + if ($test instanceof TestCase || $test instanceof PhptTestCase) { + $tests[] = $test->valueObjectForEvents(); + } + } + } +} diff --git a/src/Event/Value/TestSuite/TestSuiteForTestClass.php b/src/Event/Value/TestSuite/TestSuiteForTestClass.php new file mode 100644 index 00000000000..34ad9d5eac3 --- /dev/null +++ b/src/Event/Value/TestSuite/TestSuiteForTestClass.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteForTestClass extends TestSuite +{ + /** + * @var class-string + */ + private string $className; + private string $file; + private int $line; + + /** + * @param class-string $name + */ + public function __construct(string $name, int $size, TestCollection $tests, string $file, int $line) + { + parent::__construct($name, $size, $tests); + + $this->className = $name; + $this->file = $file; + $this->line = $line; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + public function file(): string + { + return $this->file; + } + + public function line(): int + { + return $this->line; + } + + public function isForTestClass(): true + { + return true; + } +} diff --git a/src/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php b/src/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php new file mode 100644 index 00000000000..67a94391dd5 --- /dev/null +++ b/src/Event/Value/TestSuite/TestSuiteForTestMethodWithDataProvider.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteForTestMethodWithDataProvider extends TestSuite +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + private string $file; + private int $line; + + /** + * @param non-empty-string $name + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $name, int $size, TestCollection $tests, string $className, string $methodName, string $file, int $line) + { + parent::__construct($name, $size, $tests); + + $this->className = $className; + $this->methodName = $methodName; + $this->file = $file; + $this->line = $line; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function file(): string + { + return $this->file; + } + + public function line(): int + { + return $this->line; + } + + public function isForTestMethodWithDataProvider(): true + { + return true; + } +} diff --git a/src/Event/Value/TestSuite/TestSuiteWithName.php b/src/Event/Value/TestSuite/TestSuiteWithName.php new file mode 100644 index 00000000000..4823fb26333 --- /dev/null +++ b/src/Event/Value/TestSuite/TestSuiteWithName.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteWithName extends TestSuite +{ + public function isWithName(): true + { + return true; + } +} diff --git a/src/Event/Value/Throwable.php b/src/Event/Value/Throwable.php new file mode 100644 index 00000000000..e48cf1a3ac6 --- /dev/null +++ b/src/Event/Value/Throwable.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use const PHP_EOL; +use PHPUnit\Event\NoPreviousThrowableException; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Throwable +{ + /** + * @var class-string + */ + private string $className; + private string $message; + private string $description; + private string $stackTrace; + private ?Throwable $previous; + + /** + * @param class-string $className + */ + public function __construct(string $className, string $message, string $description, string $stackTrace, ?self $previous) + { + $this->className = $className; + $this->message = $message; + $this->description = $description; + $this->stackTrace = $stackTrace; + $this->previous = $previous; + } + + /** + * @throws NoPreviousThrowableException + */ + public function asString(): string + { + $buffer = $this->description(); + + if ($this->stackTrace() !== '') { + $buffer .= PHP_EOL . $this->stackTrace(); + } + + if ($this->hasPrevious()) { + $buffer .= PHP_EOL . 'Caused by' . PHP_EOL . $this->previous()->asString(); + } + + return $buffer; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + public function message(): string + { + return $this->message; + } + + public function description(): string + { + return $this->description; + } + + public function stackTrace(): string + { + return $this->stackTrace; + } + + /** + * @phpstan-assert-if-true !null $this->previous + */ + public function hasPrevious(): bool + { + return $this->previous !== null; + } + + /** + * @throws NoPreviousThrowableException + */ + public function previous(): self + { + if ($this->previous === null) { + throw new NoPreviousThrowableException; + } + + return $this->previous; + } +} diff --git a/src/Event/Value/ThrowableBuilder.php b/src/Event/Value/ThrowableBuilder.php new file mode 100644 index 00000000000..7db4beea721 --- /dev/null +++ b/src/Event/Value/ThrowableBuilder.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Exception; +use PHPUnit\Util\Filter; +use PHPUnit\Util\ThrowableToStringMapper; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ThrowableBuilder +{ + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + public static function from(\Throwable $t): Throwable + { + $previous = $t->getPrevious(); + + if ($previous !== null) { + $previous = self::from($previous); + } + + return new Throwable( + $t::class, + $t->getMessage(), + ThrowableToStringMapper::map($t), + Filter::stackTraceFromThrowableAsString($t, false), + $previous, + ); + } +} diff --git a/src/Exception.php b/src/Exception.php new file mode 100644 index 00000000000..7a8302e20d0 --- /dev/null +++ b/src/Exception.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} diff --git a/src/Framework/Assert.php b/src/Framework/Assert.php new file mode 100644 index 00000000000..5692d8fd722 --- /dev/null +++ b/src/Framework/Assert.php @@ -0,0 +1,3002 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_combine; +use function array_intersect_key; +use function class_exists; +use function count; +use function file_get_contents; +use function interface_exists; +use function is_bool; +use ArrayAccess; +use Countable; +use Generator; +use PHPUnit\Framework\Constraint\ArrayHasKey; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\Count; +use PHPUnit\Framework\Constraint\DirectoryExists; +use PHPUnit\Framework\Constraint\FileExists; +use PHPUnit\Framework\Constraint\GreaterThan; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEmpty; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\Constraint\IsEqualCanonicalizing; +use PHPUnit\Framework\Constraint\IsEqualIgnoringCase; +use PHPUnit\Framework\Constraint\IsEqualWithDelta; +use PHPUnit\Framework\Constraint\IsFalse; +use PHPUnit\Framework\Constraint\IsFinite; +use PHPUnit\Framework\Constraint\IsIdentical; +use PHPUnit\Framework\Constraint\IsInfinite; +use PHPUnit\Framework\Constraint\IsInstanceOf; +use PHPUnit\Framework\Constraint\IsJson; +use PHPUnit\Framework\Constraint\IsList; +use PHPUnit\Framework\Constraint\IsNan; +use PHPUnit\Framework\Constraint\IsNull; +use PHPUnit\Framework\Constraint\IsReadable; +use PHPUnit\Framework\Constraint\IsTrue; +use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Constraint\IsWritable; +use PHPUnit\Framework\Constraint\JsonMatches; +use PHPUnit\Framework\Constraint\LessThan; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\LogicalOr; +use PHPUnit\Framework\Constraint\LogicalXor; +use PHPUnit\Framework\Constraint\ObjectEquals; +use PHPUnit\Framework\Constraint\ObjectHasProperty; +use PHPUnit\Framework\Constraint\RegularExpression; +use PHPUnit\Framework\Constraint\SameSize; +use PHPUnit\Framework\Constraint\StringContains; +use PHPUnit\Framework\Constraint\StringEndsWith; +use PHPUnit\Framework\Constraint\StringEqualsStringIgnoringLineEndings; +use PHPUnit\Framework\Constraint\StringMatchesFormatDescription; +use PHPUnit\Framework\Constraint\StringStartsWith; +use PHPUnit\Framework\Constraint\TraversableContainsEqual; +use PHPUnit\Framework\Constraint\TraversableContainsIdentical; +use PHPUnit\Framework\Constraint\TraversableContainsOnly; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Assert +{ + private static int $count = 0; + + /** + * Asserts that two arrays are equal while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsEqualToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + $filteredExpected = []; + + foreach ($keysToBeConsidered as $key) { + if (isset($expected[$key])) { + $filteredExpected[$key] = $expected[$key]; + } + } + + $filteredActual = []; + + foreach ($keysToBeConsidered as $key) { + if (isset($actual[$key])) { + $filteredActual[$key] = $actual[$key]; + } + } + + self::assertEquals($filteredExpected, $filteredActual, $message); + } + + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsEqualToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + foreach ($keysToBeIgnored as $key) { + unset($expected[$key], $actual[$key]); + } + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two arrays are identical while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + $keysToBeConsidered = array_combine($keysToBeConsidered, $keysToBeConsidered); + $expected = array_intersect_key($expected, $keysToBeConsidered); + $actual = array_intersect_key($actual, $keysToBeConsidered); + + self::assertSame($expected, $actual, $message); + } + + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayIsIdenticalToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + foreach ($keysToBeIgnored as $key) { + unset($expected[$key], $actual[$key]); + } + + self::assertSame($expected, $actual, $message); + } + + /** + * Asserts that an array has a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + $constraint = new ArrayHasKey($key); + + self::assertThat($array, $constraint, $message); + } + + /** + * Asserts that an array does not have a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertArrayNotHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + $constraint = new LogicalNot( + new ArrayHasKey($key), + ); + + self::assertThat($array, $constraint, $message); + } + + /** + * @phpstan-assert list $array + * + * @throws ExpectationFailedException + */ + final public static function assertIsList(mixed $array, string $message = ''): void + { + self::assertThat( + $array, + new IsList, + $message, + ); + } + + /** + * Asserts that a haystack contains a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContains(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new TraversableContainsIdentical($needle); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new TraversableContainsEqual($needle); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack does not contain a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertNotContains(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new LogicalNot( + new TraversableContainsIdentical($needle), + ); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertNotContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new TraversableContainsEqual($needle)); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a haystack contains only values of type array. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyArray(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Array, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type bool. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyBool(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Bool, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type callable. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyCallable(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Callable, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type float. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyFloat(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Float, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type int. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyInt(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Int, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type iterable. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyIterable(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Iterable, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type null. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyNull(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Null, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type numeric. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyNumeric(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Numeric, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type object. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyObject(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Object, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyResource(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Resource, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type closed resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyClosedResource(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::ClosedResource, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type scalar. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyScalar(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::Scalar, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only values of type string. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyString(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forNativeType( + NativeType::String, + ), + $message, + ); + } + + /** + * Asserts that a haystack contains only instances of a specified interface or class name. + * + * @template T + * + * @phpstan-assert iterable $haystack + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + TraversableContainsOnly::forClassOrInterface($className), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type array. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyArray(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Array, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type bool. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyBool(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Bool, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type callable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyCallable(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Callable, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type float. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyFloat(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Float, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type int. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyInt(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Int, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type iterable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyIterable(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Iterable, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type null. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyNull(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Null, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type numeric. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyNumeric(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Numeric, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type object. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyObject(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Object, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyResource(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Resource, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type closed resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyClosedResource(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::ClosedResource, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type scalar. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyScalar(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::Scalar, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only values of type string. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyString(iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forNativeType( + NativeType::String, + ), + ), + $message, + ); + } + + /** + * Asserts that a haystack does not contain only instances of a specified interface or class name. + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + */ + final public static function assertContainsNotOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + self::assertThat( + $haystack, + new LogicalNot( + TraversableContainsOnly::forClassOrInterface($className), + ), + $message, + ); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + if ($haystack instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$haystack'); + } + + self::assertThat( + $haystack, + new Count($expectedCount), + $message, + ); + } + + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + if ($haystack instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$haystack'); + } + + $constraint = new LogicalNot( + new Count($expectedCount), + ); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that two variables are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertEquals(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqual($expected); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqualCanonicalizing($expected); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new IsEqualIgnoringCase($expected); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are equal (with delta). + * + * @throws ExpectationFailedException + */ + final public static function assertEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + $constraint = new IsEqualWithDelta( + $expected, + $delta, + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertNotEquals(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqual($expected), + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqualCanonicalizing($expected), + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqualIgnoringCase($expected), + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * Asserts that two variables are not equal (with delta). + * + * @throws ExpectationFailedException + */ + final public static function assertNotEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + $constraint = new LogicalNot( + new IsEqualWithDelta( + $expected, + $delta, + ), + ); + + self::assertThat($actual, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + self::assertThat( + $actual, + self::objectEquals($expected, $method), + $message, + ); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertObjectNotEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + self::assertThat( + $actual, + self::logicalNot( + self::objectEquals($expected, $method), + ), + $message, + ); + } + + /** + * Asserts that a variable is empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertEmpty(mixed $actual, string $message = ''): void + { + if ($actual instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$actual'); + } + + self::assertThat($actual, self::isEmpty(), $message); + } + + /** + * Asserts that a variable is not empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotEmpty(mixed $actual, string $message = ''): void + { + if ($actual instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$actual'); + } + + self::assertThat($actual, self::logicalNot(self::isEmpty()), $message); + } + + /** + * Asserts that a value is greater than another value. + * + * @throws ExpectationFailedException + */ + final public static function assertGreaterThan(mixed $minimum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::greaterThan($minimum), $message); + } + + /** + * Asserts that a value is greater than or equal to another value. + * + * @throws ExpectationFailedException + */ + final public static function assertGreaterThanOrEqual(mixed $minimum, mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + self::greaterThanOrEqual($minimum), + $message, + ); + } + + /** + * Asserts that a value is smaller than another value. + * + * @throws ExpectationFailedException + */ + final public static function assertLessThan(mixed $maximum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::lessThan($maximum), $message); + } + + /** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + */ + final public static function assertLessThanOrEqual(mixed $maximum, mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::lessThanOrEqual($maximum), $message); + } + + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @throws ExpectationFailedException + */ + final public static function assertFileEquals(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new IsEqual(file_get_contents($expected)); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new IsEqualCanonicalizing( + file_get_contents($expected), + ); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new IsEqualIgnoringCase(file_get_contents($expected)); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEquals(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new LogicalNot( + new IsEqual(file_get_contents($expected)), + ); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new LogicalNot( + new IsEqualCanonicalizing(file_get_contents($expected)), + ); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + self::assertFileExists($expected, $message); + self::assertFileExists($actual, $message); + + $constraint = new LogicalNot( + new IsEqualIgnoringCase(file_get_contents($expected)), + ); + + self::assertThat(file_get_contents($actual), $constraint, $message); + } + + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new IsEqual(file_get_contents($expectedFile)); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new IsEqualCanonicalizing(file_get_contents($expectedFile)); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new IsEqualIgnoringCase(file_get_contents($expectedFile)); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new LogicalNot( + new IsEqual(file_get_contents($expectedFile)), + ); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new LogicalNot( + new IsEqualCanonicalizing(file_get_contents($expectedFile)), + ); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + */ + final public static function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $constraint = new LogicalNot( + new IsEqualIgnoringCase(file_get_contents($expectedFile)), + ); + + self::assertThat($actualString, $constraint, $message); + } + + /** + * Asserts that a file/dir is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsReadable(string $filename, string $message = ''): void + { + self::assertThat($filename, new IsReadable, $message); + } + + /** + * Asserts that a file/dir exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsNotReadable(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new IsReadable), $message); + } + + /** + * Asserts that a file/dir exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsWritable(string $filename, string $message = ''): void + { + self::assertThat($filename, new IsWritable, $message); + } + + /** + * Asserts that a file/dir exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertIsNotWritable(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new IsWritable), $message); + } + + /** + * Asserts that a directory exists. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryExists(string $directory, string $message = ''): void + { + self::assertThat($directory, new DirectoryExists, $message); + } + + /** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryDoesNotExist(string $directory, string $message = ''): void + { + self::assertThat($directory, new LogicalNot(new DirectoryExists), $message); + } + + /** + * Asserts that a directory exists and is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsReadable($directory, $message); + } + + /** + * Asserts that a directory exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsNotReadable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsNotReadable($directory, $message); + } + + /** + * Asserts that a directory exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsWritable($directory, $message); + } + + /** + * Asserts that a directory exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertDirectoryIsNotWritable(string $directory, string $message = ''): void + { + self::assertDirectoryExists($directory, $message); + self::assertIsNotWritable($directory, $message); + } + + /** + * Asserts that a file exists. + * + * @throws ExpectationFailedException + */ + final public static function assertFileExists(string $filename, string $message = ''): void + { + self::assertThat($filename, new FileExists, $message); + } + + /** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + */ + final public static function assertFileDoesNotExist(string $filename, string $message = ''): void + { + self::assertThat($filename, new LogicalNot(new FileExists), $message); + } + + /** + * Asserts that a file exists and is readable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsReadable($file, $message); + } + + /** + * Asserts that a file exists and is not readable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsNotReadable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsNotReadable($file, $message); + } + + /** + * Asserts that a file exists and is writable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsWritable($file, $message); + } + + /** + * Asserts that a file exists and is not writable. + * + * @throws ExpectationFailedException + */ + final public static function assertFileIsNotWritable(string $file, string $message = ''): void + { + self::assertFileExists($file, $message); + self::assertIsNotWritable($file, $message); + } + + /** + * Asserts that a condition is true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert true $condition + */ + final public static function assertTrue(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::isTrue(), $message); + } + + /** + * Asserts that a condition is not true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !true $condition + */ + final public static function assertNotTrue(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::logicalNot(self::isTrue()), $message); + } + + /** + * Asserts that a condition is false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert false $condition + */ + final public static function assertFalse(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::isFalse(), $message); + } + + /** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !false $condition + */ + final public static function assertNotFalse(mixed $condition, string $message = ''): void + { + self::assertThat($condition, self::logicalNot(self::isFalse()), $message); + } + + /** + * Asserts that a variable is null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert null $actual + */ + final public static function assertNull(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isNull(), $message); + } + + /** + * Asserts that a variable is not null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !null $actual + */ + final public static function assertNotNull(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::logicalNot(self::isNull()), $message); + } + + /** + * Asserts that a variable is finite. + * + * @throws ExpectationFailedException + */ + final public static function assertFinite(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isFinite(), $message); + } + + /** + * Asserts that a variable is infinite. + * + * @throws ExpectationFailedException + */ + final public static function assertInfinite(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isInfinite(), $message); + } + + /** + * Asserts that a variable is nan. + * + * @throws ExpectationFailedException + */ + final public static function assertNan(mixed $actual, string $message = ''): void + { + self::assertThat($actual, self::isNan(), $message); + } + + /** + * Asserts that an object has a specified property. + * + * @throws ExpectationFailedException + */ + final public static function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void + { + self::assertThat( + $object, + new ObjectHasProperty($propertyName), + $message, + ); + } + + /** + * Asserts that an object does not have a specified property. + * + * @throws ExpectationFailedException + */ + final public static function assertObjectNotHasProperty(string $propertyName, object $object, string $message = ''): void + { + self::assertThat( + $object, + new LogicalNot( + new ObjectHasProperty($propertyName), + ), + $message, + ); + } + + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @template ExpectedType + * + * @param ExpectedType $expected + * + * @throws ExpectationFailedException + * + * @phpstan-assert =ExpectedType $actual + */ + final public static function assertSame(mixed $expected, mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsIdentical($expected), + $message, + ); + } + + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @throws ExpectationFailedException + */ + final public static function assertNotSame(mixed $expected, mixed $actual, string $message = ''): void + { + if (is_bool($expected) && is_bool($actual)) { + self::assertNotEquals($expected, $actual, $message); + } + + self::assertThat( + $actual, + new LogicalNot( + new IsIdentical($expected), + ), + $message, + ); + } + + /** + * Asserts that a variable is of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * @throws UnknownClassOrInterfaceException + * + * @phpstan-assert =ExpectedType $actual + */ + final public static function assertInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + if (!class_exists($expected) && !interface_exists($expected)) { + throw new UnknownClassOrInterfaceException($expected); + } + + self::assertThat( + $actual, + new IsInstanceOf($expected), + $message, + ); + } + + /** + * Asserts that a variable is not of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !ExpectedType $actual + */ + final public static function assertNotInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + if (!class_exists($expected) && !interface_exists($expected)) { + throw new UnknownClassOrInterfaceException($expected); + } + + self::assertThat( + $actual, + new LogicalNot( + new IsInstanceOf($expected), + ), + $message, + ); + } + + /** + * Asserts that a variable is of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert array $actual + */ + final public static function assertIsArray(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Array), + $message, + ); + } + + /** + * Asserts that a variable is of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert bool $actual + */ + final public static function assertIsBool(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Bool), + $message, + ); + } + + /** + * Asserts that a variable is of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert float $actual + */ + final public static function assertIsFloat(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Float), + $message, + ); + } + + /** + * Asserts that a variable is of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert int $actual + */ + final public static function assertIsInt(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Int), + $message, + ); + } + + /** + * Asserts that a variable is of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert numeric $actual + */ + final public static function assertIsNumeric(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Numeric), + $message, + ); + } + + /** + * Asserts that a variable is of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert object $actual + */ + final public static function assertIsObject(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Object), + $message, + ); + } + + /** + * Asserts that a variable is of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + */ + final public static function assertIsResource(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Resource), + $message, + ); + } + + /** + * Asserts that a variable is of type resource and is closed. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + */ + final public static function assertIsClosedResource(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::ClosedResource), + $message, + ); + } + + /** + * Asserts that a variable is of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert string $actual + */ + final public static function assertIsString(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::String), + $message, + ); + } + + /** + * Asserts that a variable is of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert scalar $actual + */ + final public static function assertIsScalar(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Scalar), + $message, + ); + } + + /** + * Asserts that a variable is of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert callable $actual + */ + final public static function assertIsCallable(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Callable), + $message, + ); + } + + /** + * Asserts that a variable is of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert iterable $actual + */ + final public static function assertIsIterable(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new IsType(NativeType::Iterable), + $message, + ); + } + + /** + * Asserts that a variable is not of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !array $actual + */ + final public static function assertIsNotArray(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Array)), + $message, + ); + } + + /** + * Asserts that a variable is not of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !bool $actual + */ + final public static function assertIsNotBool(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Bool)), + $message, + ); + } + + /** + * Asserts that a variable is not of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !float $actual + */ + final public static function assertIsNotFloat(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Float)), + $message, + ); + } + + /** + * Asserts that a variable is not of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !int $actual + */ + final public static function assertIsNotInt(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Int)), + $message, + ); + } + + /** + * Asserts that a variable is not of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !numeric $actual + */ + final public static function assertIsNotNumeric(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Numeric)), + $message, + ); + } + + /** + * Asserts that a variable is not of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !object $actual + */ + final public static function assertIsNotObject(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Object)), + $message, + ); + } + + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + */ + final public static function assertIsNotResource(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Resource)), + $message, + ); + } + + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + */ + final public static function assertIsNotClosedResource(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::ClosedResource)), + $message, + ); + } + + /** + * Asserts that a variable is not of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !string $actual + */ + final public static function assertIsNotString(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::String)), + $message, + ); + } + + /** + * Asserts that a variable is not of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !scalar $actual + */ + final public static function assertIsNotScalar(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Scalar)), + $message, + ); + } + + /** + * Asserts that a variable is not of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !callable $actual + */ + final public static function assertIsNotCallable(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Callable)), + $message, + ); + } + + /** + * Asserts that a variable is not of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !iterable $actual + */ + final public static function assertIsNotIterable(mixed $actual, string $message = ''): void + { + self::assertThat( + $actual, + new LogicalNot(new IsType(NativeType::Iterable)), + $message, + ); + } + + /** + * Asserts that a string matches a given regular expression. + * + * @throws ExpectationFailedException + */ + final public static function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + self::assertThat($string, new RegularExpression($pattern), $message); + } + + /** + * Asserts that a string does not match a given regular expression. + * + * @throws ExpectationFailedException + */ + final public static function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void + { + self::assertThat( + $string, + new LogicalNot( + new RegularExpression($pattern), + ), + $message, + ); + } + + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + if ($expected instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$expected'); + } + + if ($actual instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$actual'); + } + + self::assertThat( + $actual, + new SameSize($expected), + $message, + ); + } + + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is not the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + */ + final public static function assertNotSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + if ($expected instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$expected'); + } + + if ($actual instanceof Generator) { + throw GeneratorNotSupportedException::fromParameterName('$actual'); + } + + self::assertThat( + $actual, + new LogicalNot( + new SameSize($expected), + ), + $message, + ); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsStringIgnoringLineEndings(string $needle, string $haystack, string $message = ''): void + { + self::assertThat($haystack, new StringContains($needle, false, true), $message); + } + + /** + * Asserts that two strings are equal except for line endings. + * + * @throws ExpectationFailedException + */ + final public static function assertStringEqualsStringIgnoringLineEndings(string $expected, string $actual, string $message = ''): void + { + self::assertThat($actual, new StringEqualsStringIgnoringLineEndings($expected), $message); + } + + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertFileMatchesFormat(string $format, string $actualFile, string $message = ''): void + { + self::assertFileExists($actualFile, $message); + + self::assertThat( + file_get_contents($actualFile), + new StringMatchesFormatDescription($format), + $message, + ); + } + + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertFileMatchesFormatFile(string $formatFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($formatFile, $message); + self::assertFileExists($actualFile, $message); + + $formatDescription = file_get_contents($formatFile); + + self::assertIsString($formatDescription); + + self::assertThat( + file_get_contents($actualFile), + new StringMatchesFormatDescription($formatDescription), + $message, + ); + } + + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + */ + final public static function assertStringMatchesFormat(string $format, string $string, string $message = ''): void + { + self::assertThat($string, new StringMatchesFormatDescription($format), $message); + } + + /** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + */ + final public static function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + self::assertFileExists($formatFile, $message); + + $formatDescription = file_get_contents($formatFile); + + self::assertIsString($formatDescription); + + self::assertThat( + $string, + new StringMatchesFormatDescription( + $formatDescription, + ), + $message, + ); + } + + /** + * Asserts that a string starts with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringStartsWith(string $prefix, string $string, string $message = ''): void + { + self::assertThat($string, new StringStartsWith($prefix), $message); + } + + /** + * Asserts that a string starts not with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringStartsNotWith(string $prefix, string $string, string $message = ''): void + { + self::assertThat( + $string, + new LogicalNot( + new StringStartsWith($prefix), + ), + $message, + ); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new StringContains($needle, true); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle)); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + $constraint = new LogicalNot(new StringContains($needle, true)); + + self::assertThat($haystack, $constraint, $message); + } + + /** + * Asserts that a string ends with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringEndsWith(string $suffix, string $string, string $message = ''): void + { + self::assertThat($string, new StringEndsWith($suffix), $message); + } + + /** + * Asserts that a string ends not with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + final public static function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void + { + self::assertThat( + $string, + new LogicalNot( + new StringEndsWith($suffix), + ), + $message, + ); + } + + /** + * Asserts that two XML files are equal. + * + * @throws Exception + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = (new XmlLoader)->loadFile($expectedFile); + $actual = (new XmlLoader)->loadFile($actualFile); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML files are not equal. + * + * @throws \PHPUnit\Util\Exception + * @throws ExpectationFailedException + */ + final public static function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + $expected = (new XmlLoader)->loadFile($expectedFile); + $actual = (new XmlLoader)->loadFile($actualFile); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader)->loadFile($expectedFile); + $actual = (new XmlLoader)->load($actualXml); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringNotEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader)->loadFile($expectedFile); + $actual = (new XmlLoader)->load($actualXml); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are equal. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader)->load($expectedXml); + $actual = (new XmlLoader)->load($actualXml); + + self::assertEquals($expected, $actual, $message); + } + + /** + * Asserts that two XML documents are not equal. + * + * @throws ExpectationFailedException + * @throws XmlException + */ + final public static function assertXmlStringNotEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + $expected = (new XmlLoader)->load($expectedXml); + $actual = (new XmlLoader)->load($actualXml); + + self::assertNotEquals($expected, $actual, $message); + } + + /** + * Evaluates a PHPUnit\Framework\Constraint matcher object. + * + * @throws ExpectationFailedException + */ + final public static function assertThat(mixed $value, Constraint $constraint, string $message = ''): void + { + self::$count += count($constraint); + + $constraint->evaluate($value, $message); + } + + /** + * Asserts that a string is a valid JSON string. + * + * @throws ExpectationFailedException + */ + final public static function assertJson(string $actual, string $message = ''): void + { + self::assertThat($actual, self::isJson(), $message); + } + + /** + * Asserts that two given JSON encoded objects or arrays are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + + /** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + + self::assertThat( + $actualJson, + new LogicalNot( + new JsonMatches($expectedJson), + ), + $message, + ); + } + + /** + * Asserts that the generated JSON encoded object and the content of the given file are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $expectedJson = file_get_contents($expectedFile); + + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + + /** + * Asserts that the generated JSON encoded object and the content of the given file are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $expectedJson = file_get_contents($expectedFile); + + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + self::assertJson($actualJson, $message); + + self::assertThat( + $actualJson, + new LogicalNot( + new JsonMatches($expectedJson), + ), + $message, + ); + } + + /** + * Asserts that two JSON files are equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $expectedJson = file_get_contents($expectedFile); + + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + + self::assertFileExists($actualFile, $message); + + $actualJson = file_get_contents($actualFile); + + self::assertIsString($actualJson); + self::assertJson($actualJson, $message); + + self::assertThat($actualJson, new JsonMatches($expectedJson), $message); + } + + /** + * Asserts that two JSON files are not equal. + * + * @throws ExpectationFailedException + */ + final public static function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + self::assertFileExists($expectedFile, $message); + + $expectedJson = file_get_contents($expectedFile); + + self::assertIsString($expectedJson); + self::assertJson($expectedJson, $message); + + self::assertFileExists($actualFile, $message); + + $actualJson = file_get_contents($actualFile); + + self::assertIsString($actualJson); + self::assertJson($actualJson, $message); + + self::assertThat($actualJson, self::logicalNot(new JsonMatches($expectedJson)), $message); + } + + /** + * @throws Exception + */ + final public static function logicalAnd(mixed ...$constraints): LogicalAnd + { + return LogicalAnd::fromConstraints(...$constraints); + } + + final public static function logicalOr(mixed ...$constraints): LogicalOr + { + return LogicalOr::fromConstraints(...$constraints); + } + + final public static function logicalNot(Constraint $constraint): LogicalNot + { + return new LogicalNot($constraint); + } + + final public static function logicalXor(mixed ...$constraints): LogicalXor + { + return LogicalXor::fromConstraints(...$constraints); + } + + final public static function anything(): IsAnything + { + return new IsAnything; + } + + final public static function isTrue(): IsTrue + { + return new IsTrue; + } + + /** + * @template CallbackInput of mixed + * + * @param callable(CallbackInput $callback): bool $callback + * + * @return Callback + */ + final public static function callback(callable $callback): Callback + { + return new Callback($callback); + } + + final public static function isFalse(): IsFalse + { + return new IsFalse; + } + + final public static function isJson(): IsJson + { + return new IsJson; + } + + final public static function isNull(): IsNull + { + return new IsNull; + } + + final public static function isFinite(): IsFinite + { + return new IsFinite; + } + + final public static function isInfinite(): IsInfinite + { + return new IsInfinite; + } + + final public static function isNan(): IsNan + { + return new IsNan; + } + + final public static function containsEqual(mixed $value): TraversableContainsEqual + { + return new TraversableContainsEqual($value); + } + + final public static function containsIdentical(mixed $value): TraversableContainsIdentical + { + return new TraversableContainsIdentical($value); + } + + final public static function containsOnlyArray(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Array); + } + + final public static function containsOnlyBool(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Bool); + } + + final public static function containsOnlyCallable(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Callable); + } + + final public static function containsOnlyFloat(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Float); + } + + final public static function containsOnlyInt(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Int); + } + + final public static function containsOnlyIterable(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Iterable); + } + + final public static function containsOnlyNull(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Null); + } + + final public static function containsOnlyNumeric(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Numeric); + } + + final public static function containsOnlyObject(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Object); + } + + final public static function containsOnlyResource(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Resource); + } + + final public static function containsOnlyClosedResource(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::ClosedResource); + } + + final public static function containsOnlyScalar(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::Scalar); + } + + final public static function containsOnlyString(): TraversableContainsOnly + { + return TraversableContainsOnly::forNativeType(NativeType::String); + } + + /** + * @param class-string $className + * + * @throws Exception + */ + final public static function containsOnlyInstancesOf(string $className): TraversableContainsOnly + { + return TraversableContainsOnly::forClassOrInterface($className); + } + + final public static function arrayHasKey(mixed $key): ArrayHasKey + { + return new ArrayHasKey($key); + } + + final public static function isList(): IsList + { + return new IsList; + } + + final public static function equalTo(mixed $value): IsEqual + { + return new IsEqual($value); + } + + final public static function equalToCanonicalizing(mixed $value): IsEqualCanonicalizing + { + return new IsEqualCanonicalizing($value); + } + + final public static function equalToIgnoringCase(mixed $value): IsEqualIgnoringCase + { + return new IsEqualIgnoringCase($value); + } + + final public static function equalToWithDelta(mixed $value, float $delta): IsEqualWithDelta + { + return new IsEqualWithDelta($value, $delta); + } + + final public static function isEmpty(): IsEmpty + { + return new IsEmpty; + } + + final public static function isWritable(): IsWritable + { + return new IsWritable; + } + + final public static function isReadable(): IsReadable + { + return new IsReadable; + } + + final public static function directoryExists(): DirectoryExists + { + return new DirectoryExists; + } + + final public static function fileExists(): FileExists + { + return new FileExists; + } + + final public static function greaterThan(mixed $value): GreaterThan + { + return new GreaterThan($value); + } + + final public static function greaterThanOrEqual(mixed $value): LogicalOr + { + return self::logicalOr( + new IsEqual($value), + new GreaterThan($value), + ); + } + + final public static function identicalTo(mixed $value): IsIdentical + { + return new IsIdentical($value); + } + + /** + * @throws UnknownClassOrInterfaceException + */ + final public static function isInstanceOf(string $className): IsInstanceOf + { + return new IsInstanceOf($className); + } + + final public static function isArray(): IsType + { + return new IsType(NativeType::Array); + } + + final public static function isBool(): IsType + { + return new IsType(NativeType::Bool); + } + + final public static function isCallable(): IsType + { + return new IsType(NativeType::Callable); + } + + final public static function isFloat(): IsType + { + return new IsType(NativeType::Float); + } + + final public static function isInt(): IsType + { + return new IsType(NativeType::Int); + } + + final public static function isIterable(): IsType + { + return new IsType(NativeType::Iterable); + } + + final public static function isNumeric(): IsType + { + return new IsType(NativeType::Numeric); + } + + final public static function isObject(): IsType + { + return new IsType(NativeType::Object); + } + + final public static function isResource(): IsType + { + return new IsType(NativeType::Resource); + } + + final public static function isClosedResource(): IsType + { + return new IsType(NativeType::ClosedResource); + } + + final public static function isScalar(): IsType + { + return new IsType(NativeType::Scalar); + } + + final public static function isString(): IsType + { + return new IsType(NativeType::String); + } + + final public static function lessThan(mixed $value): LessThan + { + return new LessThan($value); + } + + final public static function lessThanOrEqual(mixed $value): LogicalOr + { + return self::logicalOr( + new IsEqual($value), + new LessThan($value), + ); + } + + final public static function matchesRegularExpression(string $pattern): RegularExpression + { + return new RegularExpression($pattern); + } + + final public static function matches(string $string): StringMatchesFormatDescription + { + return new StringMatchesFormatDescription($string); + } + + /** + * @param non-empty-string $prefix + * + * @throws InvalidArgumentException + */ + final public static function stringStartsWith(string $prefix): StringStartsWith + { + return new StringStartsWith($prefix); + } + + final public static function stringContains(string $string, bool $case = true): StringContains + { + return new StringContains($string, $case); + } + + /** + * @param non-empty-string $suffix + * + * @throws InvalidArgumentException + */ + final public static function stringEndsWith(string $suffix): StringEndsWith + { + return new StringEndsWith($suffix); + } + + final public static function stringEqualsStringIgnoringLineEndings(string $string): StringEqualsStringIgnoringLineEndings + { + return new StringEqualsStringIgnoringLineEndings($string); + } + + final public static function countOf(int $count): Count + { + return new Count($count); + } + + final public static function objectEquals(object $object, string $method = 'equals'): ObjectEquals + { + return new ObjectEquals($object, $method); + } + + /** + * Fails a test with the given message. + * + * @throws AssertionFailedError + */ + final public static function fail(string $message = ''): never + { + self::$count++; + + throw new AssertionFailedError($message); + } + + /** + * Mark the test as incomplete. + * + * @throws IncompleteTestError + */ + final public static function markTestIncomplete(string $message = ''): never + { + throw new IncompleteTestError($message); + } + + /** + * Mark the test as skipped. + * + * @throws SkippedWithMessageException + */ + final public static function markTestSkipped(string $message = ''): never + { + throw new SkippedWithMessageException($message); + } + + /** + * Return the current assertion count. + */ + final public static function getCount(): int + { + return self::$count; + } + + /** + * Reset the assertion counter. + */ + final public static function resetCount(): void + { + self::$count = 0; + } +} diff --git a/src/Framework/Assert/Functions.php b/src/Framework/Assert/Functions.php new file mode 100644 index 00000000000..cf0d3e3b85d --- /dev/null +++ b/src/Framework/Assert/Functions.php @@ -0,0 +1,3382 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function func_get_args; +use function function_exists; +use ArrayAccess; +use Countable; +use PHPUnit\Framework\Constraint\ArrayHasKey; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\Count; +use PHPUnit\Framework\Constraint\DirectoryExists; +use PHPUnit\Framework\Constraint\FileExists; +use PHPUnit\Framework\Constraint\GreaterThan; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEmpty; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\Constraint\IsEqualCanonicalizing; +use PHPUnit\Framework\Constraint\IsEqualIgnoringCase; +use PHPUnit\Framework\Constraint\IsEqualWithDelta; +use PHPUnit\Framework\Constraint\IsFalse; +use PHPUnit\Framework\Constraint\IsFinite; +use PHPUnit\Framework\Constraint\IsIdentical; +use PHPUnit\Framework\Constraint\IsInfinite; +use PHPUnit\Framework\Constraint\IsInstanceOf; +use PHPUnit\Framework\Constraint\IsJson; +use PHPUnit\Framework\Constraint\IsList; +use PHPUnit\Framework\Constraint\IsNan; +use PHPUnit\Framework\Constraint\IsNull; +use PHPUnit\Framework\Constraint\IsReadable; +use PHPUnit\Framework\Constraint\IsTrue; +use PHPUnit\Framework\Constraint\IsType; +use PHPUnit\Framework\Constraint\IsWritable; +use PHPUnit\Framework\Constraint\LessThan; +use PHPUnit\Framework\Constraint\LogicalAnd; +use PHPUnit\Framework\Constraint\LogicalNot; +use PHPUnit\Framework\Constraint\LogicalOr; +use PHPUnit\Framework\Constraint\LogicalXor; +use PHPUnit\Framework\Constraint\ObjectEquals; +use PHPUnit\Framework\Constraint\RegularExpression; +use PHPUnit\Framework\Constraint\StringContains; +use PHPUnit\Framework\Constraint\StringEndsWith; +use PHPUnit\Framework\Constraint\StringEqualsStringIgnoringLineEndings; +use PHPUnit\Framework\Constraint\StringMatchesFormatDescription; +use PHPUnit\Framework\Constraint\StringStartsWith; +use PHPUnit\Framework\Constraint\TraversableContainsEqual; +use PHPUnit\Framework\Constraint\TraversableContainsIdentical; +use PHPUnit\Framework\Constraint\TraversableContainsOnly; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; +use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; +use PHPUnit\Util\Xml\XmlException; +use Throwable; + +if (!function_exists('PHPUnit\Framework\assertArrayIsEqualToArrayOnlyConsideringListOfKeys')) { + /** + * Asserts that two arrays are equal while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsEqualToArrayOnlyConsideringListOfKeys + */ + function assertArrayIsEqualToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + Assert::assertArrayIsEqualToArrayOnlyConsideringListOfKeys(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertArrayIsEqualToArrayIgnoringListOfKeys')) { + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsEqualToArrayIgnoringListOfKeys + */ + function assertArrayIsEqualToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + Assert::assertArrayIsEqualToArrayIgnoringListOfKeys(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys')) { + /** + * Asserts that two arrays are identical while only considering a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeConsidered + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys + */ + function assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(array $expected, array $actual, array $keysToBeConsidered, string $message = ''): void + { + Assert::assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertArrayIsIdenticalToArrayIgnoringListOfKeys')) { + /** + * Asserts that two arrays are equal while ignoring a list of keys. + * + * @param array $expected + * @param array $actual + * @param non-empty-list $keysToBeIgnored + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys + */ + function assertArrayIsIdenticalToArrayIgnoringListOfKeys(array $expected, array $actual, array $keysToBeIgnored, string $message = ''): void + { + Assert::assertArrayIsIdenticalToArrayIgnoringListOfKeys(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertArrayHasKey')) { + /** + * Asserts that an array has a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayHasKey + */ + function assertArrayHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + Assert::assertArrayHasKey(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertArrayNotHasKey')) { + /** + * Asserts that an array does not have a specified key. + * + * @param array|ArrayAccess $array + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertArrayNotHasKey + */ + function assertArrayNotHasKey(mixed $key, array|ArrayAccess $array, string $message = ''): void + { + Assert::assertArrayNotHasKey(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsList')) { + /** + * @phpstan-assert list $array + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsList + */ + function assertIsList(mixed $array, string $message = ''): void + { + Assert::assertIsList(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContains')) { + /** + * Asserts that a haystack contains a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContains + */ + function assertContains(mixed $needle, iterable $haystack, string $message = ''): void + { + Assert::assertContains(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsEquals')) { + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsEquals + */ + function assertContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + Assert::assertContainsEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotContains')) { + /** + * Asserts that a haystack does not contain a needle. + * + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotContains + */ + function assertNotContains(mixed $needle, iterable $haystack, string $message = ''): void + { + Assert::assertNotContains(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotContainsEquals')) { + /** + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotContainsEquals + */ + function assertNotContainsEquals(mixed $needle, iterable $haystack, string $message = ''): void + { + Assert::assertNotContainsEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyArray')) { + /** + * Asserts that a haystack contains only values of type array. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyArray + */ + function assertContainsOnlyArray(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyBool')) { + /** + * Asserts that a haystack contains only values of type bool. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyBool + */ + function assertContainsOnlyBool(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyCallable')) { + /** + * Asserts that a haystack contains only values of type callable. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyCallable + */ + function assertContainsOnlyCallable(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyFloat')) { + /** + * Asserts that a haystack contains only values of type float. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyFloat + */ + function assertContainsOnlyFloat(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyInt')) { + /** + * Asserts that a haystack contains only values of type int. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyInt + */ + function assertContainsOnlyInt(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyIterable')) { + /** + * Asserts that a haystack contains only values of type iterable. + * + * @phpstan-assert iterable> $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyIterable + */ + function assertContainsOnlyIterable(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyNull')) { + /** + * Asserts that a haystack contains only values of type null. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyNull + */ + function assertContainsOnlyNull(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyNumeric')) { + /** + * Asserts that a haystack contains only values of type numeric. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyNumeric + */ + function assertContainsOnlyNumeric(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyObject')) { + /** + * Asserts that a haystack contains only values of type object. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyObject + */ + function assertContainsOnlyObject(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyResource')) { + /** + * Asserts that a haystack contains only values of type resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyResource + */ + function assertContainsOnlyResource(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyClosedResource')) { + /** + * Asserts that a haystack contains only values of type closed resource. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyClosedResource + */ + function assertContainsOnlyClosedResource(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyScalar')) { + /** + * Asserts that a haystack contains only values of type scalar. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyScalar + */ + function assertContainsOnlyScalar(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyString')) { + /** + * Asserts that a haystack contains only values of type string. + * + * @phpstan-assert iterable $haystack + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyString + */ + function assertContainsOnlyString(iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsOnlyInstancesOf')) { + /** + * Asserts that a haystack contains only instances of a specified interface or class name. + * + * @template T + * + * @phpstan-assert iterable $haystack + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsOnlyInstancesOf + */ + function assertContainsOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + Assert::assertContainsOnlyInstancesOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyArray')) { + /** + * Asserts that a haystack does not contain only values of type array. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyArray + */ + function assertContainsNotOnlyArray(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyBool')) { + /** + * Asserts that a haystack does not contain only values of type bool. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyBool + */ + function assertContainsNotOnlyBool(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyCallable')) { + /** + * Asserts that a haystack does not contain only values of type callable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyCallable + */ + function assertContainsNotOnlyCallable(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyFloat')) { + /** + * Asserts that a haystack does not contain only values of type float. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyFloat + */ + function assertContainsNotOnlyFloat(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyInt')) { + /** + * Asserts that a haystack does not contain only values of type int. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyInt + */ + function assertContainsNotOnlyInt(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyIterable')) { + /** + * Asserts that a haystack does not contain only values of type iterable. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyIterable + */ + function assertContainsNotOnlyIterable(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyNull')) { + /** + * Asserts that a haystack does not contain only values of type null. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyNull + */ + function assertContainsNotOnlyNull(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyNumeric')) { + /** + * Asserts that a haystack does not contain only values of type numeric. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyNumeric + */ + function assertContainsNotOnlyNumeric(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyObject')) { + /** + * Asserts that a haystack does not contain only values of type object. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyObject + */ + function assertContainsNotOnlyObject(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyResource')) { + /** + * Asserts that a haystack does not contain only values of type resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyResource + */ + function assertContainsNotOnlyResource(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyClosedResource')) { + /** + * Asserts that a haystack does not contain only values of type closed resource. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyClosedResource + */ + function assertContainsNotOnlyClosedResource(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyScalar')) { + /** + * Asserts that a haystack does not contain only values of type scalar. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyScalar + */ + function assertContainsNotOnlyScalar(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyString')) { + /** + * Asserts that a haystack does not contain only values of type string. + * + * @param iterable $haystack + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyString + */ + function assertContainsNotOnlyString(iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertContainsNotOnlyInstancesOf')) { + /** + * Asserts that a haystack does not contain only instances of a specified interface or class name. + * + * @param class-string $className + * @param iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertContainsNotOnlyInstancesOf + */ + function assertContainsNotOnlyInstancesOf(string $className, iterable $haystack, string $message = ''): void + { + Assert::assertContainsNotOnlyInstancesOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertCount')) { + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertCount + */ + function assertCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + Assert::assertCount(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotCount')) { + /** + * Asserts the number of elements of an array, Countable or Traversable. + * + * @param Countable|iterable $haystack + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotCount + */ + function assertNotCount(int $expectedCount, Countable|iterable $haystack, string $message = ''): void + { + Assert::assertNotCount(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertEquals')) { + /** + * Asserts that two variables are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEquals + */ + function assertEquals(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertEqualsCanonicalizing')) { + /** + * Asserts that two variables are equal (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsCanonicalizing + */ + function assertEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertEqualsCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertEqualsIgnoringCase')) { + /** + * Asserts that two variables are equal (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsIgnoringCase + */ + function assertEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertEqualsIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertEqualsWithDelta')) { + /** + * Asserts that two variables are equal (with delta). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEqualsWithDelta + */ + function assertEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + Assert::assertEqualsWithDelta(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotEquals')) { + /** + * Asserts that two variables are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEquals + */ + function assertNotEquals(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertNotEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotEqualsCanonicalizing')) { + /** + * Asserts that two variables are not equal (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsCanonicalizing + */ + function assertNotEqualsCanonicalizing(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertNotEqualsCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotEqualsIgnoringCase')) { + /** + * Asserts that two variables are not equal (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsIgnoringCase + */ + function assertNotEqualsIgnoringCase(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertNotEqualsIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotEqualsWithDelta')) { + /** + * Asserts that two variables are not equal (with delta). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEqualsWithDelta + */ + function assertNotEqualsWithDelta(mixed $expected, mixed $actual, float $delta, string $message = ''): void + { + Assert::assertNotEqualsWithDelta(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertObjectEquals')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectEquals + */ + function assertObjectEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + Assert::assertObjectEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertObjectNotEquals')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectNotEquals + */ + function assertObjectNotEquals(object $expected, object $actual, string $method = 'equals', string $message = ''): void + { + Assert::assertObjectNotEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertEmpty')) { + /** + * Asserts that a variable is empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertEmpty + */ + function assertEmpty(mixed $actual, string $message = ''): void + { + Assert::assertEmpty(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotEmpty')) { + /** + * Asserts that a variable is not empty. + * + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotEmpty + */ + function assertNotEmpty(mixed $actual, string $message = ''): void + { + Assert::assertNotEmpty(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertGreaterThan')) { + /** + * Asserts that a value is greater than another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertGreaterThan + */ + function assertGreaterThan(mixed $minimum, mixed $actual, string $message = ''): void + { + Assert::assertGreaterThan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertGreaterThanOrEqual')) { + /** + * Asserts that a value is greater than or equal to another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertGreaterThanOrEqual + */ + function assertGreaterThanOrEqual(mixed $minimum, mixed $actual, string $message = ''): void + { + Assert::assertGreaterThanOrEqual(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertLessThan')) { + /** + * Asserts that a value is smaller than another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertLessThan + */ + function assertLessThan(mixed $maximum, mixed $actual, string $message = ''): void + { + Assert::assertLessThan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertLessThanOrEqual')) { + /** + * Asserts that a value is smaller than or equal to another value. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertLessThanOrEqual + */ + function assertLessThanOrEqual(mixed $maximum, mixed $actual, string $message = ''): void + { + Assert::assertLessThanOrEqual(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileEquals')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEquals + */ + function assertFileEquals(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileEqualsCanonicalizing')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEqualsCanonicalizing + */ + function assertFileEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileEqualsCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileEqualsIgnoringCase')) { + /** + * Asserts that the contents of one file is equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileEqualsIgnoringCase + */ + function assertFileEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileEqualsIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileNotEquals')) { + /** + * Asserts that the contents of one file is not equal to the contents of + * another file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEquals + */ + function assertFileNotEquals(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileNotEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileNotEqualsCanonicalizing')) { + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEqualsCanonicalizing + */ + function assertFileNotEqualsCanonicalizing(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileNotEqualsCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileNotEqualsIgnoringCase')) { + /** + * Asserts that the contents of one file is not equal to the contents of another + * file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileNotEqualsIgnoringCase + */ + function assertFileNotEqualsIgnoringCase(string $expected, string $actual, string $message = ''): void + { + Assert::assertFileNotEqualsIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEqualsFile')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFile + */ + function assertStringEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringEqualsFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEqualsFileCanonicalizing')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFileCanonicalizing + */ + function assertStringEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringEqualsFileCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEqualsFileIgnoringCase')) { + /** + * Asserts that the contents of a string is equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsFileIgnoringCase + */ + function assertStringEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringEqualsFileIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFile')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFile + */ + function assertStringNotEqualsFile(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringNotEqualsFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileCanonicalizing')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (canonicalizing). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFileCanonicalizing + */ + function assertStringNotEqualsFileCanonicalizing(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringNotEqualsFileCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringNotEqualsFileIgnoringCase')) { + /** + * Asserts that the contents of a string is not equal + * to the contents of a file (ignoring case). + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotEqualsFileIgnoringCase + */ + function assertStringNotEqualsFileIgnoringCase(string $expectedFile, string $actualString, string $message = ''): void + { + Assert::assertStringNotEqualsFileIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsReadable')) { + /** + * Asserts that a file/dir is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsReadable + */ + function assertIsReadable(string $filename, string $message = ''): void + { + Assert::assertIsReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotReadable')) { + /** + * Asserts that a file/dir exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotReadable + */ + function assertIsNotReadable(string $filename, string $message = ''): void + { + Assert::assertIsNotReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsWritable')) { + /** + * Asserts that a file/dir exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsWritable + */ + function assertIsWritable(string $filename, string $message = ''): void + { + Assert::assertIsWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotWritable')) { + /** + * Asserts that a file/dir exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotWritable + */ + function assertIsNotWritable(string $filename, string $message = ''): void + { + Assert::assertIsNotWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryExists')) { + /** + * Asserts that a directory exists. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryExists + */ + function assertDirectoryExists(string $directory, string $message = ''): void + { + Assert::assertDirectoryExists(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryDoesNotExist')) { + /** + * Asserts that a directory does not exist. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryDoesNotExist + */ + function assertDirectoryDoesNotExist(string $directory, string $message = ''): void + { + Assert::assertDirectoryDoesNotExist(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryIsReadable')) { + /** + * Asserts that a directory exists and is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsReadable + */ + function assertDirectoryIsReadable(string $directory, string $message = ''): void + { + Assert::assertDirectoryIsReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotReadable')) { + /** + * Asserts that a directory exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsNotReadable + */ + function assertDirectoryIsNotReadable(string $directory, string $message = ''): void + { + Assert::assertDirectoryIsNotReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryIsWritable')) { + /** + * Asserts that a directory exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsWritable + */ + function assertDirectoryIsWritable(string $directory, string $message = ''): void + { + Assert::assertDirectoryIsWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDirectoryIsNotWritable')) { + /** + * Asserts that a directory exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDirectoryIsNotWritable + */ + function assertDirectoryIsNotWritable(string $directory, string $message = ''): void + { + Assert::assertDirectoryIsNotWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileExists')) { + /** + * Asserts that a file exists. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileExists + */ + function assertFileExists(string $filename, string $message = ''): void + { + Assert::assertFileExists(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileDoesNotExist')) { + /** + * Asserts that a file does not exist. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileDoesNotExist + */ + function assertFileDoesNotExist(string $filename, string $message = ''): void + { + Assert::assertFileDoesNotExist(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileIsReadable')) { + /** + * Asserts that a file exists and is readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsReadable + */ + function assertFileIsReadable(string $file, string $message = ''): void + { + Assert::assertFileIsReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileIsNotReadable')) { + /** + * Asserts that a file exists and is not readable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsNotReadable + */ + function assertFileIsNotReadable(string $file, string $message = ''): void + { + Assert::assertFileIsNotReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileIsWritable')) { + /** + * Asserts that a file exists and is writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsWritable + */ + function assertFileIsWritable(string $file, string $message = ''): void + { + Assert::assertFileIsWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileIsNotWritable')) { + /** + * Asserts that a file exists and is not writable. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileIsNotWritable + */ + function assertFileIsNotWritable(string $file, string $message = ''): void + { + Assert::assertFileIsNotWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertTrue')) { + /** + * Asserts that a condition is true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert true $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertTrue + */ + function assertTrue(mixed $condition, string $message = ''): void + { + Assert::assertTrue(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotTrue')) { + /** + * Asserts that a condition is not true. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !true $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotTrue + */ + function assertNotTrue(mixed $condition, string $message = ''): void + { + Assert::assertNotTrue(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFalse')) { + /** + * Asserts that a condition is false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert false $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFalse + */ + function assertFalse(mixed $condition, string $message = ''): void + { + Assert::assertFalse(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotFalse')) { + /** + * Asserts that a condition is not false. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !false $condition + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotFalse + */ + function assertNotFalse(mixed $condition, string $message = ''): void + { + Assert::assertNotFalse(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNull')) { + /** + * Asserts that a variable is null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert null $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNull + */ + function assertNull(mixed $actual, string $message = ''): void + { + Assert::assertNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotNull')) { + /** + * Asserts that a variable is not null. + * + * @throws ExpectationFailedException + * + * @phpstan-assert !null $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotNull + */ + function assertNotNull(mixed $actual, string $message = ''): void + { + Assert::assertNotNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFinite')) { + /** + * Asserts that a variable is finite. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFinite + */ + function assertFinite(mixed $actual, string $message = ''): void + { + Assert::assertFinite(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertInfinite')) { + /** + * Asserts that a variable is infinite. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertInfinite + */ + function assertInfinite(mixed $actual, string $message = ''): void + { + Assert::assertInfinite(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNan')) { + /** + * Asserts that a variable is nan. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNan + */ + function assertNan(mixed $actual, string $message = ''): void + { + Assert::assertNan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertObjectHasProperty')) { + /** + * Asserts that an object has a specified property. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectHasProperty + */ + function assertObjectHasProperty(string $propertyName, object $object, string $message = ''): void + { + Assert::assertObjectHasProperty(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertObjectNotHasProperty')) { + /** + * Asserts that an object does not have a specified property. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertObjectNotHasProperty + */ + function assertObjectNotHasProperty(string $propertyName, object $object, string $message = ''): void + { + Assert::assertObjectNotHasProperty(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertSame')) { + /** + * Asserts that two variables have the same type and value. + * Used on objects, it asserts that two variables reference + * the same object. + * + * @template ExpectedType + * + * @param ExpectedType $expected + * + * @throws ExpectationFailedException + * + * @phpstan-assert =ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertSame + */ + function assertSame(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertSame(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotSame')) { + /** + * Asserts that two variables do not have the same type and value. + * Used on objects, it asserts that two variables do not reference + * the same object. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotSame + */ + function assertNotSame(mixed $expected, mixed $actual, string $message = ''): void + { + Assert::assertNotSame(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertInstanceOf')) { + /** + * Asserts that a variable is of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * @throws UnknownClassOrInterfaceException + * + * @phpstan-assert =ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertInstanceOf + */ + function assertInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + Assert::assertInstanceOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotInstanceOf')) { + /** + * Asserts that a variable is not of a given type. + * + * @template ExpectedType of object + * + * @param class-string $expected + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !ExpectedType $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotInstanceOf + */ + function assertNotInstanceOf(string $expected, mixed $actual, string $message = ''): void + { + Assert::assertNotInstanceOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsArray')) { + /** + * Asserts that a variable is of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert array $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsArray + */ + function assertIsArray(mixed $actual, string $message = ''): void + { + Assert::assertIsArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsBool')) { + /** + * Asserts that a variable is of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert bool $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsBool + */ + function assertIsBool(mixed $actual, string $message = ''): void + { + Assert::assertIsBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsFloat')) { + /** + * Asserts that a variable is of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert float $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsFloat + */ + function assertIsFloat(mixed $actual, string $message = ''): void + { + Assert::assertIsFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsInt')) { + /** + * Asserts that a variable is of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert int $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsInt + */ + function assertIsInt(mixed $actual, string $message = ''): void + { + Assert::assertIsInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNumeric')) { + /** + * Asserts that a variable is of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert numeric $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNumeric + */ + function assertIsNumeric(mixed $actual, string $message = ''): void + { + Assert::assertIsNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsObject')) { + /** + * Asserts that a variable is of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert object $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsObject + */ + function assertIsObject(mixed $actual, string $message = ''): void + { + Assert::assertIsObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsResource')) { + /** + * Asserts that a variable is of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsResource + */ + function assertIsResource(mixed $actual, string $message = ''): void + { + Assert::assertIsResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsClosedResource')) { + /** + * Asserts that a variable is of type resource and is closed. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsClosedResource + */ + function assertIsClosedResource(mixed $actual, string $message = ''): void + { + Assert::assertIsClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsString')) { + /** + * Asserts that a variable is of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert string $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsString + */ + function assertIsString(mixed $actual, string $message = ''): void + { + Assert::assertIsString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsScalar')) { + /** + * Asserts that a variable is of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert scalar $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsScalar + */ + function assertIsScalar(mixed $actual, string $message = ''): void + { + Assert::assertIsScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsCallable')) { + /** + * Asserts that a variable is of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert callable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsCallable + */ + function assertIsCallable(mixed $actual, string $message = ''): void + { + Assert::assertIsCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsIterable')) { + /** + * Asserts that a variable is of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert iterable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsIterable + */ + function assertIsIterable(mixed $actual, string $message = ''): void + { + Assert::assertIsIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotArray')) { + /** + * Asserts that a variable is not of type array. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !array $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotArray + */ + function assertIsNotArray(mixed $actual, string $message = ''): void + { + Assert::assertIsNotArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotBool')) { + /** + * Asserts that a variable is not of type bool. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !bool $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotBool + */ + function assertIsNotBool(mixed $actual, string $message = ''): void + { + Assert::assertIsNotBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotFloat')) { + /** + * Asserts that a variable is not of type float. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !float $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotFloat + */ + function assertIsNotFloat(mixed $actual, string $message = ''): void + { + Assert::assertIsNotFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotInt')) { + /** + * Asserts that a variable is not of type int. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !int $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotInt + */ + function assertIsNotInt(mixed $actual, string $message = ''): void + { + Assert::assertIsNotInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotNumeric')) { + /** + * Asserts that a variable is not of type numeric. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !numeric $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotNumeric + */ + function assertIsNotNumeric(mixed $actual, string $message = ''): void + { + Assert::assertIsNotNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotObject')) { + /** + * Asserts that a variable is not of type object. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !object $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotObject + */ + function assertIsNotObject(mixed $actual, string $message = ''): void + { + Assert::assertIsNotObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotResource')) { + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotResource + */ + function assertIsNotResource(mixed $actual, string $message = ''): void + { + Assert::assertIsNotResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotClosedResource')) { + /** + * Asserts that a variable is not of type resource. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !resource $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotClosedResource + */ + function assertIsNotClosedResource(mixed $actual, string $message = ''): void + { + Assert::assertIsNotClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotString')) { + /** + * Asserts that a variable is not of type string. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !string $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotString + */ + function assertIsNotString(mixed $actual, string $message = ''): void + { + Assert::assertIsNotString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotScalar')) { + /** + * Asserts that a variable is not of type scalar. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !scalar $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotScalar + */ + function assertIsNotScalar(mixed $actual, string $message = ''): void + { + Assert::assertIsNotScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotCallable')) { + /** + * Asserts that a variable is not of type callable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !callable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotCallable + */ + function assertIsNotCallable(mixed $actual, string $message = ''): void + { + Assert::assertIsNotCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertIsNotIterable')) { + /** + * Asserts that a variable is not of type iterable. + * + * @throws Exception + * @throws ExpectationFailedException + * + * @phpstan-assert !iterable $actual + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertIsNotIterable + */ + function assertIsNotIterable(mixed $actual, string $message = ''): void + { + Assert::assertIsNotIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertMatchesRegularExpression')) { + /** + * Asserts that a string matches a given regular expression. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertMatchesRegularExpression + */ + function assertMatchesRegularExpression(string $pattern, string $string, string $message = ''): void + { + Assert::assertMatchesRegularExpression(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertDoesNotMatchRegularExpression')) { + /** + * Asserts that a string does not match a given regular expression. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertDoesNotMatchRegularExpression + */ + function assertDoesNotMatchRegularExpression(string $pattern, string $string, string $message = ''): void + { + Assert::assertDoesNotMatchRegularExpression(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertSameSize')) { + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertSameSize + */ + function assertSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + Assert::assertSameSize(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertNotSameSize')) { + /** + * Assert that the size of two arrays (or `Countable` or `Traversable` objects) + * is not the same. + * + * @param Countable|iterable $expected + * @param Countable|iterable $actual + * + * @throws Exception + * @throws ExpectationFailedException + * @throws GeneratorNotSupportedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertNotSameSize + */ + function assertNotSameSize(Countable|iterable $expected, Countable|iterable $actual, string $message = ''): void + { + Assert::assertNotSameSize(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringLineEndings')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsStringIgnoringLineEndings + */ + function assertStringContainsStringIgnoringLineEndings(string $needle, string $haystack, string $message = ''): void + { + Assert::assertStringContainsStringIgnoringLineEndings(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEqualsStringIgnoringLineEndings')) { + /** + * Asserts that two strings are equal except for line endings. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEqualsStringIgnoringLineEndings + */ + function assertStringEqualsStringIgnoringLineEndings(string $expected, string $actual, string $message = ''): void + { + Assert::assertStringEqualsStringIgnoringLineEndings(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileMatchesFormat')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileMatchesFormat + */ + function assertFileMatchesFormat(string $format, string $actualFile, string $message = ''): void + { + Assert::assertFileMatchesFormat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertFileMatchesFormatFile')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertFileMatchesFormatFile + */ + function assertFileMatchesFormatFile(string $formatFile, string $actualFile, string $message = ''): void + { + Assert::assertFileMatchesFormatFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringMatchesFormat')) { + /** + * Asserts that a string matches a given format string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringMatchesFormat + */ + function assertStringMatchesFormat(string $format, string $string, string $message = ''): void + { + Assert::assertStringMatchesFormat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringMatchesFormatFile')) { + /** + * Asserts that a string matches a given format file. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringMatchesFormatFile + */ + function assertStringMatchesFormatFile(string $formatFile, string $string, string $message = ''): void + { + Assert::assertStringMatchesFormatFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringStartsWith')) { + /** + * Asserts that a string starts with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringStartsWith + */ + function assertStringStartsWith(string $prefix, string $string, string $message = ''): void + { + Assert::assertStringStartsWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringStartsNotWith')) { + /** + * Asserts that a string starts not with a given prefix. + * + * @param non-empty-string $prefix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringStartsNotWith + */ + function assertStringStartsNotWith(string $prefix, string $string, string $message = ''): void + { + Assert::assertStringStartsNotWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringContainsString')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsString + */ + function assertStringContainsString(string $needle, string $haystack, string $message = ''): void + { + Assert::assertStringContainsString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringContainsStringIgnoringCase')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringContainsStringIgnoringCase + */ + function assertStringContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + Assert::assertStringContainsStringIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringNotContainsString')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotContainsString + */ + function assertStringNotContainsString(string $needle, string $haystack, string $message = ''): void + { + Assert::assertStringNotContainsString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringNotContainsStringIgnoringCase')) { + /** + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringNotContainsStringIgnoringCase + */ + function assertStringNotContainsStringIgnoringCase(string $needle, string $haystack, string $message = ''): void + { + Assert::assertStringNotContainsStringIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEndsWith')) { + /** + * Asserts that a string ends with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEndsWith + */ + function assertStringEndsWith(string $suffix, string $string, string $message = ''): void + { + Assert::assertStringEndsWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertStringEndsNotWith')) { + /** + * Asserts that a string ends not with a given suffix. + * + * @param non-empty-string $suffix + * + * @throws ExpectationFailedException + * @throws InvalidArgumentException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertStringEndsNotWith + */ + function assertStringEndsNotWith(string $suffix, string $string, string $message = ''): void + { + Assert::assertStringEndsNotWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlFileEqualsXmlFile')) { + /** + * Asserts that two XML files are equal. + * + * @throws Exception + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlFileEqualsXmlFile + */ + function assertXmlFileEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + Assert::assertXmlFileEqualsXmlFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlFileNotEqualsXmlFile')) { + /** + * Asserts that two XML files are not equal. + * + * @throws \PHPUnit\Util\Exception + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlFileNotEqualsXmlFile + */ + function assertXmlFileNotEqualsXmlFile(string $expectedFile, string $actualFile, string $message = ''): void + { + Assert::assertXmlFileNotEqualsXmlFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlFile')) { + /** + * Asserts that two XML documents are equal. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringEqualsXmlFile + */ + function assertXmlStringEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + Assert::assertXmlStringEqualsXmlFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlFile')) { + /** + * Asserts that two XML documents are not equal. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringNotEqualsXmlFile + */ + function assertXmlStringNotEqualsXmlFile(string $expectedFile, string $actualXml, string $message = ''): void + { + Assert::assertXmlStringNotEqualsXmlFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlStringEqualsXmlString')) { + /** + * Asserts that two XML documents are equal. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringEqualsXmlString + */ + function assertXmlStringEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + Assert::assertXmlStringEqualsXmlString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertXmlStringNotEqualsXmlString')) { + /** + * Asserts that two XML documents are not equal. + * + * @throws ExpectationFailedException + * @throws XmlException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertXmlStringNotEqualsXmlString + */ + function assertXmlStringNotEqualsXmlString(string $expectedXml, string $actualXml, string $message = ''): void + { + Assert::assertXmlStringNotEqualsXmlString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertThat')) { + /** + * Evaluates a PHPUnit\Framework\Constraint matcher object. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertThat + */ + function assertThat(mixed $value, Constraint $constraint, string $message = ''): void + { + Assert::assertThat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJson')) { + /** + * Asserts that a string is a valid JSON string. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJson + */ + function assertJson(string $actual, string $message = ''): void + { + Assert::assertJson(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonString')) { + /** + * Asserts that two given JSON encoded objects or arrays are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringEqualsJsonString + */ + function assertJsonStringEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + Assert::assertJsonStringEqualsJsonString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonString')) { + /** + * Asserts that two given JSON encoded objects or arrays are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringNotEqualsJsonString + */ + function assertJsonStringNotEqualsJsonString(string $expectedJson, string $actualJson, string $message = ''): void + { + Assert::assertJsonStringNotEqualsJsonString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonStringEqualsJsonFile')) { + /** + * Asserts that the generated JSON encoded object and the content of the given file are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringEqualsJsonFile + */ + function assertJsonStringEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + Assert::assertJsonStringEqualsJsonFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonStringNotEqualsJsonFile')) { + /** + * Asserts that the generated JSON encoded object and the content of the given file are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonStringNotEqualsJsonFile + */ + function assertJsonStringNotEqualsJsonFile(string $expectedFile, string $actualJson, string $message = ''): void + { + Assert::assertJsonStringNotEqualsJsonFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonFileEqualsJsonFile')) { + /** + * Asserts that two JSON files are equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonFileEqualsJsonFile + */ + function assertJsonFileEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + Assert::assertJsonFileEqualsJsonFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\assertJsonFileNotEqualsJsonFile')) { + /** + * Asserts that two JSON files are not equal. + * + * @throws ExpectationFailedException + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @see Assert::assertJsonFileNotEqualsJsonFile + */ + function assertJsonFileNotEqualsJsonFile(string $expectedFile, string $actualFile, string $message = ''): void + { + Assert::assertJsonFileNotEqualsJsonFile(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\logicalAnd')) { + function logicalAnd(mixed ...$constraints): LogicalAnd + { + return Assert::logicalAnd(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\logicalOr')) { + function logicalOr(mixed ...$constraints): LogicalOr + { + return Assert::logicalOr(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\logicalNot')) { + function logicalNot(Constraint $constraint): LogicalNot + { + return Assert::logicalNot(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\logicalXor')) { + function logicalXor(mixed ...$constraints): LogicalXor + { + return Assert::logicalXor(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\anything')) { + function anything(): IsAnything + { + return Assert::anything(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isTrue')) { + function isTrue(): IsTrue + { + return Assert::isTrue(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isFalse')) { + function isFalse(): IsFalse + { + return Assert::isFalse(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isJson')) { + function isJson(): IsJson + { + return Assert::isJson(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isNull')) { + function isNull(): IsNull + { + return Assert::isNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isFinite')) { + function isFinite(): IsFinite + { + return Assert::isFinite(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isInfinite')) { + function isInfinite(): IsInfinite + { + return Assert::isInfinite(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isNan')) { + function isNan(): IsNan + { + return Assert::isNan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsEqual')) { + function containsEqual(mixed $value): TraversableContainsEqual + { + return Assert::containsEqual(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsIdentical')) { + function containsIdentical(mixed $value): TraversableContainsIdentical + { + return Assert::containsIdentical(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyArray')) { + function containsOnlyArray(): TraversableContainsOnly + { + return Assert::containsOnlyArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyBool')) { + function containsOnlyBool(): TraversableContainsOnly + { + return Assert::containsOnlyBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyCallable')) { + function containsOnlyCallable(): TraversableContainsOnly + { + return Assert::containsOnlyCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyFloat')) { + function containsOnlyFloat(): TraversableContainsOnly + { + return Assert::containsOnlyFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyInt')) { + function containsOnlyInt(): TraversableContainsOnly + { + return Assert::containsOnlyInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyIterable')) { + function containsOnlyIterable(): TraversableContainsOnly + { + return Assert::containsOnlyIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyNull')) { + function containsOnlyNull(): TraversableContainsOnly + { + return Assert::containsOnlyNull(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyNumeric')) { + function containsOnlyNumeric(): TraversableContainsOnly + { + return Assert::containsOnlyNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyObject')) { + function containsOnlyObject(): TraversableContainsOnly + { + return Assert::containsOnlyObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyResource')) { + function containsOnlyResource(): TraversableContainsOnly + { + return Assert::containsOnlyResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyClosedResource')) { + function containsOnlyClosedResource(): TraversableContainsOnly + { + return Assert::containsOnlyClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyScalar')) { + function containsOnlyScalar(): TraversableContainsOnly + { + return Assert::containsOnlyScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyString')) { + function containsOnlyString(): TraversableContainsOnly + { + return Assert::containsOnlyString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\containsOnlyInstancesOf')) { + function containsOnlyInstancesOf(string $className): TraversableContainsOnly + { + return Assert::containsOnlyInstancesOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\arrayHasKey')) { + function arrayHasKey(mixed $key): ArrayHasKey + { + return Assert::arrayHasKey(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isList')) { + function isList(): IsList + { + return Assert::isList(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\equalTo')) { + function equalTo(mixed $value): IsEqual + { + return Assert::equalTo(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\equalToCanonicalizing')) { + function equalToCanonicalizing(mixed $value): IsEqualCanonicalizing + { + return Assert::equalToCanonicalizing(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\equalToIgnoringCase')) { + function equalToIgnoringCase(mixed $value): IsEqualIgnoringCase + { + return Assert::equalToIgnoringCase(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\equalToWithDelta')) { + function equalToWithDelta(mixed $value, float $delta): IsEqualWithDelta + { + return Assert::equalToWithDelta(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isEmpty')) { + function isEmpty(): IsEmpty + { + return Assert::isEmpty(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isWritable')) { + function isWritable(): IsWritable + { + return Assert::isWritable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isReadable')) { + function isReadable(): IsReadable + { + return Assert::isReadable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\directoryExists')) { + function directoryExists(): DirectoryExists + { + return Assert::directoryExists(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\fileExists')) { + function fileExists(): FileExists + { + return Assert::fileExists(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\greaterThan')) { + function greaterThan(mixed $value): GreaterThan + { + return Assert::greaterThan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\greaterThanOrEqual')) { + function greaterThanOrEqual(mixed $value): LogicalOr + { + return Assert::greaterThanOrEqual(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\identicalTo')) { + function identicalTo(mixed $value): IsIdentical + { + return Assert::identicalTo(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isInstanceOf')) { + function isInstanceOf(string $className): IsInstanceOf + { + return Assert::isInstanceOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isArray')) { + function isArray(): IsType + { + return Assert::isArray(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isBool')) { + function isBool(): IsType + { + return Assert::isBool(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isCallable')) { + function isCallable(): IsType + { + return Assert::isCallable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isFloat')) { + function isFloat(): IsType + { + return Assert::isFloat(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isInt')) { + function isInt(): IsType + { + return Assert::isInt(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isIterable')) { + function isIterable(): IsType + { + return Assert::isIterable(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isNumeric')) { + function isNumeric(): IsType + { + return Assert::isNumeric(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isObject')) { + function isObject(): IsType + { + return Assert::isObject(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isResource')) { + function isResource(): IsType + { + return Assert::isResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isClosedResource')) { + function isClosedResource(): IsType + { + return Assert::isClosedResource(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isScalar')) { + function isScalar(): IsType + { + return Assert::isScalar(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\isString')) { + function isString(): IsType + { + return Assert::isString(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\lessThan')) { + function lessThan(mixed $value): LessThan + { + return Assert::lessThan(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\lessThanOrEqual')) { + function lessThanOrEqual(mixed $value): LogicalOr + { + return Assert::lessThanOrEqual(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\matchesRegularExpression')) { + function matchesRegularExpression(string $pattern): RegularExpression + { + return Assert::matchesRegularExpression(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\matches')) { + function matches(string $string): StringMatchesFormatDescription + { + return Assert::matches(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\stringStartsWith')) { + function stringStartsWith(string $prefix): StringStartsWith + { + return Assert::stringStartsWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\stringContains')) { + function stringContains(string $string, bool $case = true): StringContains + { + return Assert::stringContains(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\stringEndsWith')) { + function stringEndsWith(string $suffix): StringEndsWith + { + return Assert::stringEndsWith(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\stringEqualsStringIgnoringLineEndings')) { + function stringEqualsStringIgnoringLineEndings(string $string): StringEqualsStringIgnoringLineEndings + { + return Assert::stringEqualsStringIgnoringLineEndings(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\countOf')) { + function countOf(int $count): Count + { + return Assert::countOf(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\objectEquals')) { + function objectEquals(object $object, string $method = 'equals'): ObjectEquals + { + return Assert::objectEquals(...func_get_args()); + } +} + +if (!function_exists('PHPUnit\Framework\callback')) { + /** + * @template CallbackInput of mixed + * + * @param callable(CallbackInput $callback): bool $callback + * + * @return Callback + */ + function callback(callable $callback): Callback + { + return Assert::callback($callback); + } +} + +if (!function_exists('PHPUnit\Framework\any')) { + /** + * Returns a matcher that matches when the method is executed + * zero or more times. + */ + function any(): AnyInvokedCountMatcher + { + return new AnyInvokedCountMatcher; + } +} + +if (!function_exists('PHPUnit\Framework\never')) { + /** + * Returns a matcher that matches when the method is never executed. + */ + function never(): InvokedCountMatcher + { + return new InvokedCountMatcher(0); + } +} + +if (!function_exists('PHPUnit\Framework\atLeast')) { + /** + * Returns a matcher that matches when the method is executed + * at least N times. + */ + function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher + { + return new InvokedAtLeastCountMatcher( + $requiredInvocations, + ); + } +} + +if (!function_exists('PHPUnit\Framework\atLeastOnce')) { + /** + * Returns a matcher that matches when the method is executed at least once. + */ + function atLeastOnce(): InvokedAtLeastOnceMatcher + { + return new InvokedAtLeastOnceMatcher; + } +} + +if (!function_exists('PHPUnit\Framework\once')) { + /** + * Returns a matcher that matches when the method is executed exactly once. + */ + function once(): InvokedCountMatcher + { + return new InvokedCountMatcher(1); + } +} + +if (!function_exists('PHPUnit\Framework\exactly')) { + /** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */ + function exactly(int $count): InvokedCountMatcher + { + return new InvokedCountMatcher($count); + } +} + +if (!function_exists('PHPUnit\Framework\atMost')) { + /** + * Returns a matcher that matches when the method is executed + * at most N times. + */ + function atMost(int $allowedInvocations): InvokedAtMostCountMatcher + { + return new InvokedAtMostCountMatcher($allowedInvocations); + } +} + +if (!function_exists('PHPUnit\Framework\throwException')) { + function throwException(Throwable $exception): ExceptionStub + { + return new ExceptionStub($exception); + } +} diff --git a/src/Framework/Attributes/After.php b/src/Framework/Attributes/After.php new file mode 100644 index 00000000000..6d36d29138f --- /dev/null +++ b/src/Framework/Attributes/After.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class After +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/AfterClass.php b/src/Framework/Attributes/AfterClass.php new file mode 100644 index 00000000000..d4a9d6f4c5e --- /dev/null +++ b/src/Framework/Attributes/AfterClass.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class AfterClass +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/AllowMockObjectsWithoutExpectations.php b/src/Framework/Attributes/AllowMockObjectsWithoutExpectations.php new file mode 100644 index 00000000000..4b8e3849a11 --- /dev/null +++ b/src/Framework/Attributes/AllowMockObjectsWithoutExpectations.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class AllowMockObjectsWithoutExpectations +{ +} diff --git a/src/Framework/Attributes/BackupGlobals.php b/src/Framework/Attributes/BackupGlobals.php new file mode 100644 index 00000000000..f9526ca281f --- /dev/null +++ b/src/Framework/Attributes/BackupGlobals.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class BackupGlobals +{ + private bool $enabled; + + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Framework/Attributes/BackupStaticProperties.php b/src/Framework/Attributes/BackupStaticProperties.php new file mode 100644 index 00000000000..e633cf88a95 --- /dev/null +++ b/src/Framework/Attributes/BackupStaticProperties.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class BackupStaticProperties +{ + private bool $enabled; + + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Framework/Attributes/Before.php b/src/Framework/Attributes/Before.php new file mode 100644 index 00000000000..c2af00b7fa2 --- /dev/null +++ b/src/Framework/Attributes/Before.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class Before +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/BeforeClass.php b/src/Framework/Attributes/BeforeClass.php new file mode 100644 index 00000000000..2bb5a07b5f3 --- /dev/null +++ b/src/Framework/Attributes/BeforeClass.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class BeforeClass +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/CoversClass.php b/src/Framework/Attributes/CoversClass.php new file mode 100644 index 00000000000..2cf0b2dd267 --- /dev/null +++ b/src/Framework/Attributes/CoversClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClass +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/CoversClassesThatExtendClass.php b/src/Framework/Attributes/CoversClassesThatExtendClass.php new file mode 100644 index 00000000000..486fc5b0a7a --- /dev/null +++ b/src/Framework/Attributes/CoversClassesThatExtendClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClassesThatExtendClass +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/CoversClassesThatImplementInterface.php b/src/Framework/Attributes/CoversClassesThatImplementInterface.php new file mode 100644 index 00000000000..69bcd84603b --- /dev/null +++ b/src/Framework/Attributes/CoversClassesThatImplementInterface.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversClassesThatImplementInterface +{ + /** + * @var class-string + */ + private string $interfaceName; + + /** + * @param class-string $interfaceName + */ + public function __construct(string $interfaceName) + { + $this->interfaceName = $interfaceName; + } + + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} diff --git a/src/Framework/Attributes/CoversFunction.php b/src/Framework/Attributes/CoversFunction.php new file mode 100644 index 00000000000..3b58b1914d0 --- /dev/null +++ b/src/Framework/Attributes/CoversFunction.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Framework/Attributes/CoversMethod.php b/src/Framework/Attributes/CoversMethod.php new file mode 100644 index 00000000000..4181239b9d8 --- /dev/null +++ b/src/Framework/Attributes/CoversMethod.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversMethod +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/CoversNamespace.php b/src/Framework/Attributes/CoversNamespace.php new file mode 100644 index 00000000000..50d82b99473 --- /dev/null +++ b/src/Framework/Attributes/CoversNamespace.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversNamespace +{ + /** + * @var non-empty-string + */ + private string $namespace; + + /** + * @param non-empty-string $namespace + */ + public function __construct(string $namespace) + { + $this->namespace = $namespace; + } + + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } +} diff --git a/src/Framework/Attributes/CoversNothing.php b/src/Framework/Attributes/CoversNothing.php new file mode 100644 index 00000000000..33ce31f30f1 --- /dev/null +++ b/src/Framework/Attributes/CoversNothing.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class CoversNothing +{ +} diff --git a/src/Framework/Attributes/CoversTrait.php b/src/Framework/Attributes/CoversTrait.php new file mode 100644 index 00000000000..89927855053 --- /dev/null +++ b/src/Framework/Attributes/CoversTrait.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class CoversTrait +{ + /** + * @var trait-string + */ + private string $traitName; + + /** + * @param trait-string $traitName + */ + public function __construct(string $traitName) + { + $this->traitName = $traitName; + } + + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} diff --git a/src/Framework/Attributes/DataProvider.php b/src/Framework/Attributes/DataProvider.php new file mode 100644 index 00000000000..fc4a822f64f --- /dev/null +++ b/src/Framework/Attributes/DataProvider.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DataProvider +{ + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName, bool $validateArgumentCount = true) + { + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} diff --git a/src/Framework/Attributes/DataProviderExternal.php b/src/Framework/Attributes/DataProviderExternal.php new file mode 100644 index 00000000000..e1f11ab131d --- /dev/null +++ b/src/Framework/Attributes/DataProviderExternal.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DataProviderExternal +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName, bool $validateArgumentCount = true) + { + $this->className = $className; + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} diff --git a/src/Framework/Attributes/Depends.php b/src/Framework/Attributes/Depends.php new file mode 100644 index 00000000000..1375ae5bdaa --- /dev/null +++ b/src/Framework/Attributes/Depends.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Depends +{ + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DependsExternal.php b/src/Framework/Attributes/DependsExternal.php new file mode 100644 index 00000000000..c2f9e39f0b4 --- /dev/null +++ b/src/Framework/Attributes/DependsExternal.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternal +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DependsExternalUsingDeepClone.php b/src/Framework/Attributes/DependsExternalUsingDeepClone.php new file mode 100644 index 00000000000..d71452b8837 --- /dev/null +++ b/src/Framework/Attributes/DependsExternalUsingDeepClone.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternalUsingDeepClone +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DependsExternalUsingShallowClone.php b/src/Framework/Attributes/DependsExternalUsingShallowClone.php new file mode 100644 index 00000000000..9fb8fbf7d8b --- /dev/null +++ b/src/Framework/Attributes/DependsExternalUsingShallowClone.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsExternalUsingShallowClone +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DependsOnClass.php b/src/Framework/Attributes/DependsOnClass.php new file mode 100644 index 00000000000..14465c77e68 --- /dev/null +++ b/src/Framework/Attributes/DependsOnClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClass +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/DependsOnClassUsingDeepClone.php b/src/Framework/Attributes/DependsOnClassUsingDeepClone.php new file mode 100644 index 00000000000..dc46c39df58 --- /dev/null +++ b/src/Framework/Attributes/DependsOnClassUsingDeepClone.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClassUsingDeepClone +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/DependsOnClassUsingShallowClone.php b/src/Framework/Attributes/DependsOnClassUsingShallowClone.php new file mode 100644 index 00000000000..5201f045d85 --- /dev/null +++ b/src/Framework/Attributes/DependsOnClassUsingShallowClone.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsOnClassUsingShallowClone +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/DependsUsingDeepClone.php b/src/Framework/Attributes/DependsUsingDeepClone.php new file mode 100644 index 00000000000..173188ec6e0 --- /dev/null +++ b/src/Framework/Attributes/DependsUsingDeepClone.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsUsingDeepClone +{ + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DependsUsingShallowClone.php b/src/Framework/Attributes/DependsUsingShallowClone.php new file mode 100644 index 00000000000..8aff52a3a2c --- /dev/null +++ b/src/Framework/Attributes/DependsUsingShallowClone.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class DependsUsingShallowClone +{ + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php b/src/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php new file mode 100644 index 00000000000..2709f569e75 --- /dev/null +++ b/src/Framework/Attributes/DisableReturnValueGenerationForTestDoubles.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class DisableReturnValueGenerationForTestDoubles +{ +} diff --git a/src/Framework/Attributes/DoesNotPerformAssertions.php b/src/Framework/Attributes/DoesNotPerformAssertions.php new file mode 100644 index 00000000000..f193e5af359 --- /dev/null +++ b/src/Framework/Attributes/DoesNotPerformAssertions.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class DoesNotPerformAssertions +{ +} diff --git a/src/Framework/Attributes/ExcludeGlobalVariableFromBackup.php b/src/Framework/Attributes/ExcludeGlobalVariableFromBackup.php new file mode 100644 index 00000000000..5d1ac72c83e --- /dev/null +++ b/src/Framework/Attributes/ExcludeGlobalVariableFromBackup.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class ExcludeGlobalVariableFromBackup +{ + /** + * @var non-empty-string + */ + private string $globalVariableName; + + /** + * @param non-empty-string $globalVariableName + */ + public function __construct(string $globalVariableName) + { + $this->globalVariableName = $globalVariableName; + } + + /** + * @return non-empty-string + */ + public function globalVariableName(): string + { + return $this->globalVariableName; + } +} diff --git a/src/Framework/Attributes/ExcludeStaticPropertyFromBackup.php b/src/Framework/Attributes/ExcludeStaticPropertyFromBackup.php new file mode 100644 index 00000000000..ea572549185 --- /dev/null +++ b/src/Framework/Attributes/ExcludeStaticPropertyFromBackup.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class ExcludeStaticPropertyFromBackup +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $propertyName; + + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public function __construct(string $className, string $propertyName) + { + $this->className = $className; + $this->propertyName = $propertyName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } +} diff --git a/src/Framework/Attributes/Group.php b/src/Framework/Attributes/Group.php new file mode 100644 index 00000000000..5a6942bb802 --- /dev/null +++ b/src/Framework/Attributes/Group.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Group +{ + /** + * @var non-empty-string + */ + private string $name; + + /** + * @param non-empty-string $name + */ + public function __construct(string $name) + { + $this->name = $name; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } +} diff --git a/src/Framework/Attributes/IgnoreDeprecations.php b/src/Framework/Attributes/IgnoreDeprecations.php new file mode 100644 index 00000000000..d137edd78e6 --- /dev/null +++ b/src/Framework/Attributes/IgnoreDeprecations.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class IgnoreDeprecations +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + + /** + * @param null|non-empty-string $messagePattern + */ + public function __construct(null|string $messagePattern = null) + { + $this->messagePattern = $messagePattern; + } + + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} diff --git a/src/Framework/Attributes/IgnorePhpunitDeprecations.php b/src/Framework/Attributes/IgnorePhpunitDeprecations.php new file mode 100644 index 00000000000..1cebec04dce --- /dev/null +++ b/src/Framework/Attributes/IgnorePhpunitDeprecations.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class IgnorePhpunitDeprecations +{ +} diff --git a/src/Framework/Attributes/IgnorePhpunitWarnings.php b/src/Framework/Attributes/IgnorePhpunitWarnings.php new file mode 100644 index 00000000000..af1d22bda92 --- /dev/null +++ b/src/Framework/Attributes/IgnorePhpunitWarnings.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class IgnorePhpunitWarnings +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + + /** + * @param null|non-empty-string $messagePattern + */ + public function __construct(null|string $messagePattern = null) + { + $this->messagePattern = $messagePattern; + } + + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} diff --git a/src/Framework/Attributes/Large.php b/src/Framework/Attributes/Large.php new file mode 100644 index 00000000000..a751a934361 --- /dev/null +++ b/src/Framework/Attributes/Large.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Large +{ +} diff --git a/src/Framework/Attributes/Medium.php b/src/Framework/Attributes/Medium.php new file mode 100644 index 00000000000..debc4b0d319 --- /dev/null +++ b/src/Framework/Attributes/Medium.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Medium +{ +} diff --git a/src/Framework/Attributes/PostCondition.php b/src/Framework/Attributes/PostCondition.php new file mode 100644 index 00000000000..8eb40fe03d6 --- /dev/null +++ b/src/Framework/Attributes/PostCondition.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class PostCondition +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/PreCondition.php b/src/Framework/Attributes/PreCondition.php new file mode 100644 index 00000000000..5f47fc599a0 --- /dev/null +++ b/src/Framework/Attributes/PreCondition.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class PreCondition +{ + private int $priority; + + public function __construct(int $priority = 0) + { + $this->priority = $priority; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Framework/Attributes/PreserveGlobalState.php b/src/Framework/Attributes/PreserveGlobalState.php new file mode 100644 index 00000000000..fcd9c637246 --- /dev/null +++ b/src/Framework/Attributes/PreserveGlobalState.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class PreserveGlobalState +{ + private bool $enabled; + + public function __construct(bool $enabled) + { + $this->enabled = $enabled; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Framework/Attributes/RequiresEnvironmentVariable.php b/src/Framework/Attributes/RequiresEnvironmentVariable.php new file mode 100644 index 00000000000..7e460b99afb --- /dev/null +++ b/src/Framework/Attributes/RequiresEnvironmentVariable.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresEnvironmentVariable +{ + private string $environmentVariableName; + private null|string $value; + + public function __construct(string $environmentVariableName, null|string $value = null) + { + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + + public function value(): null|string + { + return $this->value; + } +} diff --git a/src/Framework/Attributes/RequiresFunction.php b/src/Framework/Attributes/RequiresFunction.php new file mode 100644 index 00000000000..e358bdf116b --- /dev/null +++ b/src/Framework/Attributes/RequiresFunction.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Framework/Attributes/RequiresMethod.php b/src/Framework/Attributes/RequiresMethod.php new file mode 100644 index 00000000000..713c1ee91a2 --- /dev/null +++ b/src/Framework/Attributes/RequiresMethod.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresMethod +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/RequiresOperatingSystem.php b/src/Framework/Attributes/RequiresOperatingSystem.php new file mode 100644 index 00000000000..066d7d3c7c6 --- /dev/null +++ b/src/Framework/Attributes/RequiresOperatingSystem.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresOperatingSystem +{ + /** + * @var non-empty-string + */ + private string $regularExpression; + + /** + * @param non-empty-string $regularExpression + */ + public function __construct(string $regularExpression) + { + $this->regularExpression = $regularExpression; + } + + /** + * @return non-empty-string + */ + public function regularExpression(): string + { + return $this->regularExpression; + } +} diff --git a/src/Framework/Attributes/RequiresOperatingSystemFamily.php b/src/Framework/Attributes/RequiresOperatingSystemFamily.php new file mode 100644 index 00000000000..088ba85cea6 --- /dev/null +++ b/src/Framework/Attributes/RequiresOperatingSystemFamily.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresOperatingSystemFamily +{ + /** + * @var non-empty-string + */ + private string $operatingSystemFamily; + + /** + * @param non-empty-string $operatingSystemFamily + */ + public function __construct(string $operatingSystemFamily) + { + $this->operatingSystemFamily = $operatingSystemFamily; + } + + /** + * @return non-empty-string + */ + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} diff --git a/src/Framework/Attributes/RequiresPhp.php b/src/Framework/Attributes/RequiresPhp.php new file mode 100644 index 00000000000..94fbe51b88f --- /dev/null +++ b/src/Framework/Attributes/RequiresPhp.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresPhp +{ + /** + * @var non-empty-string + */ + private string $versionRequirement; + + /** + * @param non-empty-string $versionRequirement + */ + public function __construct(string $versionRequirement) + { + $this->versionRequirement = $versionRequirement; + } + + /** + * @return non-empty-string + */ + public function versionRequirement(): string + { + return $this->versionRequirement; + } +} diff --git a/src/Framework/Attributes/RequiresPhpExtension.php b/src/Framework/Attributes/RequiresPhpExtension.php new file mode 100644 index 00000000000..61a81ec4781 --- /dev/null +++ b/src/Framework/Attributes/RequiresPhpExtension.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresPhpExtension +{ + /** + * @var non-empty-string + */ + private string $extension; + + /** + * @var null|non-empty-string + */ + private ?string $versionRequirement; + + /** + * @param non-empty-string $extension + * @param null|non-empty-string $versionRequirement + */ + public function __construct(string $extension, ?string $versionRequirement = null) + { + $this->extension = $extension; + $this->versionRequirement = $versionRequirement; + } + + /** + * @return non-empty-string + */ + public function extension(): string + { + return $this->extension; + } + + /** + * @return null|non-empty-string + */ + public function versionRequirement(): ?string + { + return $this->versionRequirement; + } +} diff --git a/src/Framework/Attributes/RequiresPhpunit.php b/src/Framework/Attributes/RequiresPhpunit.php new file mode 100644 index 00000000000..8b26405b759 --- /dev/null +++ b/src/Framework/Attributes/RequiresPhpunit.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class RequiresPhpunit +{ + /** + * @var non-empty-string + */ + private string $versionRequirement; + + /** + * @param non-empty-string $versionRequirement + */ + public function __construct(string $versionRequirement) + { + $this->versionRequirement = $versionRequirement; + } + + /** + * @return non-empty-string + */ + public function versionRequirement(): string + { + return $this->versionRequirement; + } +} diff --git a/src/Framework/Attributes/RequiresPhpunitExtension.php b/src/Framework/Attributes/RequiresPhpunitExtension.php new file mode 100644 index 00000000000..9b6a164f248 --- /dev/null +++ b/src/Framework/Attributes/RequiresPhpunitExtension.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; +use PHPUnit\Runner\Extension\Extension; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresPhpunitExtension +{ + /** + * @var class-string + */ + private string $extensionClass; + + /** + * @param class-string $extensionClass + */ + public function __construct(string $extensionClass) + { + $this->extensionClass = $extensionClass; + } + + /** + * @return class-string + */ + public function extensionClass(): string + { + return $this->extensionClass; + } +} diff --git a/src/Framework/Attributes/RequiresSetting.php b/src/Framework/Attributes/RequiresSetting.php new file mode 100644 index 00000000000..86828dd0f01 --- /dev/null +++ b/src/Framework/Attributes/RequiresSetting.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class RequiresSetting +{ + /** + * @var non-empty-string + */ + private string $setting; + + /** + * @var non-empty-string + */ + private string $value; + + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public function __construct(string $setting, string $value) + { + $this->setting = $setting; + $this->value = $value; + } + + /** + * @return non-empty-string + */ + public function setting(): string + { + return $this->setting; + } + + /** + * @return non-empty-string + */ + public function value(): string + { + return $this->value; + } +} diff --git a/src/Framework/Attributes/RunInSeparateProcess.php b/src/Framework/Attributes/RunInSeparateProcess.php new file mode 100644 index 00000000000..740d6f38746 --- /dev/null +++ b/src/Framework/Attributes/RunInSeparateProcess.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class RunInSeparateProcess +{ +} diff --git a/src/Framework/Attributes/RunTestsInSeparateProcesses.php b/src/Framework/Attributes/RunTestsInSeparateProcesses.php new file mode 100644 index 00000000000..0f8d4320012 --- /dev/null +++ b/src/Framework/Attributes/RunTestsInSeparateProcesses.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class RunTestsInSeparateProcesses +{ +} diff --git a/src/Framework/Attributes/Small.php b/src/Framework/Attributes/Small.php new file mode 100644 index 00000000000..5ef284ab1ff --- /dev/null +++ b/src/Framework/Attributes/Small.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS)] +final readonly class Small +{ +} diff --git a/src/Framework/Attributes/Test.php b/src/Framework/Attributes/Test.php new file mode 100644 index 00000000000..a15f7f55770 --- /dev/null +++ b/src/Framework/Attributes/Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class Test +{ +} diff --git a/src/Framework/Attributes/TestDox.php b/src/Framework/Attributes/TestDox.php new file mode 100644 index 00000000000..b0478506805 --- /dev/null +++ b/src/Framework/Attributes/TestDox.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)] +final readonly class TestDox +{ + /** + * @var non-empty-string + */ + private string $text; + + /** + * @param non-empty-string $text + */ + public function __construct(string $text) + { + $this->text = $text; + } + + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} diff --git a/src/Framework/Attributes/TestDoxFormatter.php b/src/Framework/Attributes/TestDoxFormatter.php new file mode 100644 index 00000000000..0456d843f66 --- /dev/null +++ b/src/Framework/Attributes/TestDoxFormatter.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class TestDoxFormatter +{ + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/TestDoxFormatterExternal.php b/src/Framework/Attributes/TestDoxFormatterExternal.php new file mode 100644 index 00000000000..de5cf701e84 --- /dev/null +++ b/src/Framework/Attributes/TestDoxFormatterExternal.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class TestDoxFormatterExternal +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/TestWith.php b/src/Framework/Attributes/TestWith.php new file mode 100644 index 00000000000..b5c33a43e62 --- /dev/null +++ b/src/Framework/Attributes/TestWith.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class TestWith +{ + /** + * @var array + */ + private array $data; + + /** + * @var ?non-empty-string + */ + private ?string $name; + + /** + * @param array $data + * @param ?non-empty-string $name + */ + public function __construct(array $data, ?string $name = null) + { + $this->data = $data; + $this->name = $name; + } + + /** + * @return array + */ + public function data(): array + { + return $this->data; + } + + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} diff --git a/src/Framework/Attributes/TestWithJson.php b/src/Framework/Attributes/TestWithJson.php new file mode 100644 index 00000000000..bfe9c09226b --- /dev/null +++ b/src/Framework/Attributes/TestWithJson.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class TestWithJson +{ + /** + * @var non-empty-string + */ + private string $json; + + /** + * @var ?non-empty-string + */ + private ?string $name; + + /** + * @param non-empty-string $json + * @param ?non-empty-string $name + */ + public function __construct(string $json, ?string $name = null) + { + $this->json = $json; + $this->name = $name; + } + + /** + * @return non-empty-string + */ + public function json(): string + { + return $this->json; + } + + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} diff --git a/src/Framework/Attributes/Ticket.php b/src/Framework/Attributes/Ticket.php new file mode 100644 index 00000000000..e463247e2ef --- /dev/null +++ b/src/Framework/Attributes/Ticket.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class Ticket +{ + /** + * @var non-empty-string + */ + private string $text; + + /** + * @param non-empty-string $text + */ + public function __construct(string $text) + { + $this->text = $text; + } + + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} diff --git a/src/Framework/Attributes/UsesClass.php b/src/Framework/Attributes/UsesClass.php new file mode 100644 index 00000000000..f7078bce671 --- /dev/null +++ b/src/Framework/Attributes/UsesClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClass +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/UsesClassesThatExtendClass.php b/src/Framework/Attributes/UsesClassesThatExtendClass.php new file mode 100644 index 00000000000..d1aa73faa88 --- /dev/null +++ b/src/Framework/Attributes/UsesClassesThatExtendClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClassesThatExtendClass +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param class-string $className + */ + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Framework/Attributes/UsesClassesThatImplementInterface.php b/src/Framework/Attributes/UsesClassesThatImplementInterface.php new file mode 100644 index 00000000000..0f2241c8675 --- /dev/null +++ b/src/Framework/Attributes/UsesClassesThatImplementInterface.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesClassesThatImplementInterface +{ + /** + * @var class-string + */ + private string $interfaceName; + + /** + * @param class-string $interfaceName + */ + public function __construct(string $interfaceName) + { + $this->interfaceName = $interfaceName; + } + + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} diff --git a/src/Framework/Attributes/UsesFunction.php b/src/Framework/Attributes/UsesFunction.php new file mode 100644 index 00000000000..12cc408b982 --- /dev/null +++ b/src/Framework/Attributes/UsesFunction.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesFunction +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param non-empty-string $functionName + */ + public function __construct(string $functionName) + { + $this->functionName = $functionName; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Framework/Attributes/UsesMethod.php b/src/Framework/Attributes/UsesMethod.php new file mode 100644 index 00000000000..b1ee19b54d9 --- /dev/null +++ b/src/Framework/Attributes/UsesMethod.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesMethod +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + $this->className = $className; + $this->methodName = $methodName; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Framework/Attributes/UsesNamespace.php b/src/Framework/Attributes/UsesNamespace.php new file mode 100644 index 00000000000..ad929cdb128 --- /dev/null +++ b/src/Framework/Attributes/UsesNamespace.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesNamespace +{ + /** + * @var non-empty-string + */ + private string $namespace; + + /** + * @param non-empty-string $namespace + */ + public function __construct(string $namespace) + { + $this->namespace = $namespace; + } + + /** + * @return non-empty-string + */ + public function namespace(): string + { + return $this->namespace; + } +} diff --git a/src/Framework/Attributes/UsesTrait.php b/src/Framework/Attributes/UsesTrait.php new file mode 100644 index 00000000000..469e79c6866 --- /dev/null +++ b/src/Framework/Attributes/UsesTrait.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::IS_REPEATABLE)] +final readonly class UsesTrait +{ + /** + * @var trait-string + */ + private string $traitName; + + /** + * @param trait-string $traitName + */ + public function __construct(string $traitName) + { + $this->traitName = $traitName; + } + + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} diff --git a/src/Framework/Attributes/WithEnvironmentVariable.php b/src/Framework/Attributes/WithEnvironmentVariable.php new file mode 100644 index 00000000000..6d8e2d305ad --- /dev/null +++ b/src/Framework/Attributes/WithEnvironmentVariable.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final readonly class WithEnvironmentVariable +{ + /** + * @var non-empty-string + */ + private string $environmentVariableName; + private null|string $value; + + /** + * @param non-empty-string $environmentVariableName + */ + public function __construct(string $environmentVariableName, null|string $value = null) + { + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + + /** + * @return non-empty-string + */ + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + + public function value(): null|string + { + return $this->value; + } +} diff --git a/src/Framework/Attributes/WithoutErrorHandler.php b/src/Framework/Attributes/WithoutErrorHandler.php new file mode 100644 index 00000000000..a10f0fc2f16 --- /dev/null +++ b/src/Framework/Attributes/WithoutErrorHandler.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Attributes; + +use Attribute; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +#[Attribute(Attribute::TARGET_METHOD)] +final readonly class WithoutErrorHandler +{ +} diff --git a/src/Framework/Constraint/Boolean/IsFalse.php b/src/Framework/Constraint/Boolean/IsFalse.php new file mode 100644 index 00000000000..5846cf19cb0 --- /dev/null +++ b/src/Framework/Constraint/Boolean/IsFalse.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsFalse extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is false'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === false; + } +} diff --git a/src/Framework/Constraint/Boolean/IsTrue.php b/src/Framework/Constraint/Boolean/IsTrue.php new file mode 100644 index 00000000000..be589523ba4 --- /dev/null +++ b/src/Framework/Constraint/Boolean/IsTrue.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsTrue extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is true'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === true; + } +} diff --git a/src/Framework/Constraint/Callback.php b/src/Framework/Constraint/Callback.php new file mode 100644 index 00000000000..2b09ff1e082 --- /dev/null +++ b/src/Framework/Constraint/Callback.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use Closure; +use ReflectionFunction; + +/** + * @template CallbackInput of mixed + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Callback extends Constraint +{ + /** + * @var callable(CallbackInput): bool + */ + private readonly mixed $callback; + + /** + * @param callable(CallbackInput $input): bool $callback + */ + public function __construct(callable $callback) + { + $this->callback = $callback; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is accepted by specified callback'; + } + + public function isVariadic(): bool + { + return new ReflectionFunction(Closure::fromCallable($this->callback))->isVariadic(); + } + + /** + * Evaluates the constraint for parameter $value. Returns true if the + * constraint is met, false otherwise. + * + * @param CallbackInput $other + */ + protected function matches(mixed $other): bool + { + if ($this->isVariadic()) { + return ($this->callback)(...$other); + } + + return ($this->callback)($other); + } +} diff --git a/src/Framework/Constraint/Cardinality/Count.php b/src/Framework/Constraint/Cardinality/Count.php new file mode 100644 index 00000000000..2ec012a0e5a --- /dev/null +++ b/src/Framework/Constraint/Cardinality/Count.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; +use function is_countable; +use function iterator_count; +use function sprintf; +use EmptyIterator; +use Generator; +use Iterator; +use IteratorAggregate; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\GeneratorNotSupportedException; +use Traversable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +class Count extends Constraint +{ + private readonly int $expectedCount; + + public function __construct(int $expected) + { + $this->expectedCount = $expected; + } + + public function toString(): string + { + return sprintf( + 'count matches %d', + $this->expectedCount, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws Exception + */ + protected function matches(mixed $other): bool + { + return $this->expectedCount === $this->getCountOf($other); + } + + /** + * @throws Exception + */ + protected function getCountOf(mixed $other): ?int + { + if (is_countable($other)) { + return count($other); + } + + if ($other instanceof EmptyIterator) { + return 0; + } + + if ($other instanceof Traversable) { + while ($other instanceof IteratorAggregate) { + try { + $other = $other->getIterator(); + } catch (\Exception $e) { + throw new Exception( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + } + + $iterator = $other; + + if ($iterator instanceof Generator) { + throw new GeneratorNotSupportedException; + } + + if (!$iterator instanceof Iterator) { + return iterator_count($iterator); + } + + $key = $iterator->key(); + $count = iterator_count($iterator); + + // Manually rewind $iterator to previous key, since iterator_count + // moves pointer. + if ($key !== null) { + $iterator->rewind(); + + while ($iterator->valid() && $key !== $iterator->key()) { + $iterator->next(); + } + } + + return $count; + } + + return null; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @throws Exception + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + 'actual size %d matches expected size %d', + (int) $this->getCountOf($other), + $this->expectedCount, + ); + } +} diff --git a/src/Framework/Constraint/Cardinality/GreaterThan.php b/src/Framework/Constraint/Cardinality/GreaterThan.php new file mode 100644 index 00000000000..7b252dd9c86 --- /dev/null +++ b/src/Framework/Constraint/Cardinality/GreaterThan.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class GreaterThan extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is greater than ' . Exporter::export($this->value); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->value < $other; + } +} diff --git a/src/Framework/Constraint/Cardinality/IsEmpty.php b/src/Framework/Constraint/Cardinality/IsEmpty.php new file mode 100644 index 00000000000..31942d9f000 --- /dev/null +++ b/src/Framework/Constraint/Cardinality/IsEmpty.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; +use function gettype; +use function sprintf; +use function str_starts_with; +use Countable; +use EmptyIterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEmpty extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is empty'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof EmptyIterator) { + return true; + } + + if ($other instanceof Countable) { + return count($other) === 0; + } + + /** @phpstan-ignore empty.notAllowed */ + return empty($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + $type = gettype($other); + + return sprintf( + '%s %s %s', + str_starts_with($type, 'a') || str_starts_with($type, 'o') ? 'an' : 'a', + $type, + $this->toString(), + ); + } +} diff --git a/src/Framework/Constraint/Cardinality/LessThan.php b/src/Framework/Constraint/Cardinality/LessThan.php new file mode 100644 index 00000000000..122dd7347eb --- /dev/null +++ b/src/Framework/Constraint/Cardinality/LessThan.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LessThan extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is less than ' . Exporter::export($this->value); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->value > $other; + } +} diff --git a/src/Framework/Constraint/Cardinality/SameSize.php b/src/Framework/Constraint/Cardinality/SameSize.php new file mode 100644 index 00000000000..a2417a28d78 --- /dev/null +++ b/src/Framework/Constraint/Cardinality/SameSize.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use Countable; +use PHPUnit\Framework\Exception; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class SameSize extends Count +{ + /** + * @param Countable|iterable $expected + * + * @throws Exception + */ + public function __construct(Countable|iterable $expected) + { + parent::__construct((int) $this->getCountOf($expected)); + } +} diff --git a/src/Framework/Constraint/Constraint.php b/src/Framework/Constraint/Constraint.php new file mode 100644 index 00000000000..2f7028d75bb --- /dev/null +++ b/src/Framework/Constraint/Constraint.php @@ -0,0 +1,296 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function assert; +use function gettype; +use function is_int; +use function is_object; +use function sprintf; +use function str_replace; +use function strpos; +use function strtolower; +use function substr; +use Countable; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Util\Exporter; +use ReflectionObject; +use SebastianBergmann\Comparator\ComparisonFailure; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Constraint implements Countable, SelfDescribing +{ + /** + * @template A + * + * @param A $actual + * + * @return A + */ + final public function __invoke(mixed $actual): mixed + { + Assert::assertThat($actual, $this); + + return $actual; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): ?bool + { + $success = false; + + if ($this->matches($other)) { + $success = true; + } + + if ($returnResult) { + return $success; + } + + if (!$success) { + $this->fail($other, $description); + } + + return null; + } + + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return 1; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * This method can be overridden to implement the evaluation algorithm. + */ + protected function matches(mixed $other): bool + { + return false; + } + + /** + * Throws an exception for the given compared value and test description. + * + * @throws ExpectationFailedException + */ + protected function fail(mixed $other, string $description, ?ComparisonFailure $comparisonFailure = null): never + { + $failureDescription = sprintf( + 'Failed asserting that %s.', + $this->failureDescription($other), + ); + + $additionalFailureDescription = $this->additionalFailureDescription($other); + + if ($additionalFailureDescription !== '') { + $failureDescription .= "\n" . $additionalFailureDescription; + } + + if ($description !== '') { + $failureDescription = $description . "\n" . $failureDescription; + } + + throw new ExpectationFailedException( + $failureDescription, + $comparisonFailure, + ); + } + + /** + * Return additional failure description where needed. + * + * The function can be overridden to provide additional failure + * information like a diff + */ + protected function additionalFailureDescription(mixed $other): string + { + return ''; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * To provide additional failure information additionalFailureDescription + * can be used. + */ + protected function failureDescription(mixed $other): string + { + return Exporter::export($other) . ' ' . $this->toString(); + } + + /** + * Returns a custom string representation of the constraint object when it + * appears in context of an $operator expression. + * + * The purpose of this method is to provide meaningful descriptive string + * in context of operators such as LogicalNot. Native PHPUnit constraints + * are supported out of the box by LogicalNot, but externally developed + * ones had no way to provide correct strings in this context. + * + * The method shall return empty string, when it does not handle + * customization by itself. + */ + protected function toStringInContext(Operator $operator, mixed $role): string + { + return ''; + } + + /** + * Returns the description of the failure when this constraint appears in + * context of an $operator expression. + * + * The purpose of this method is to provide meaningful failure description + * in context of operators such as LogicalNot. Native PHPUnit constraints + * are supported out of the box by LogicalNot, but externally developed + * ones had no way to provide correct messages in this context. + * + * The method shall return empty string, when it does not handle + * customization by itself. + */ + protected function failureDescriptionInContext(Operator $operator, mixed $role, mixed $other): string + { + $string = $this->toStringInContext($operator, $role); + + if ($string === '') { + return ''; + } + + return Exporter::export($other) . ' ' . $string; + } + + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * Returns $this for terminal constraints and for operators that start + * non-reducible sub-expression, or the nearest descendant of $this that + * starts a non-reducible sub-expression. + * + * A constraint expression may be modelled as a tree with non-terminal + * nodes (operators) and terminal nodes. For example: + * + * LogicalOr (operator, non-terminal) + * + LogicalAnd (operator, non-terminal) + * | + IsType('int') (terminal) + * | + GreaterThan(10) (terminal) + * + LogicalNot (operator, non-terminal) + * + IsType('array') (terminal) + * + * A degenerate sub-expression is a part of the tree, that effectively does + * not contribute to the evaluation of the expression it appears in. An example + * of degenerate sub-expression is a BinaryOperator constructed with single + * operand or nested BinaryOperators, each with single operand. An + * expression involving a degenerate sub-expression is equivalent to a + * reduced expression with the degenerate sub-expression removed, for example + * + * LogicalAnd (operator) + * + LogicalOr (degenerate operator) + * | + LogicalAnd (degenerate operator) + * | + IsType('int') (terminal) + * + GreaterThan(10) (terminal) + * + * is equivalent to + * + * LogicalAnd (operator) + * + IsType('int') (terminal) + * + GreaterThan(10) (terminal) + * + * because the subexpression + * + * + LogicalOr + * + LogicalAnd + * + - + * + * is degenerate. Calling reduce() on the LogicalOr object above, as well + * as on LogicalAnd, shall return the IsType('int') instance. + * + * Other specific reductions can be implemented, for example cascade of + * LogicalNot operators + * + * + LogicalNot + * + LogicalNot + * +LogicalNot + * + IsTrue + * + * can be reduced to + * + * LogicalNot + * + IsTrue + */ + protected function reduce(): self + { + return $this; + } + + /** + * @return non-empty-string + */ + protected function valueToTypeStringFragment(mixed $value): string + { + if (is_object($value)) { + $reflector = new ReflectionObject($value); + + if ($reflector->isAnonymous()) { + $name = str_replace('class@anonymous', '', $reflector->getName()); + + $length = strpos($name, '$'); + + assert(is_int($length)); + + $name = substr($name, 0, $length); + + return 'an instance of anonymous class created at ' . $name . ' '; + } + + return 'an instance of class ' . $reflector->getName() . ' '; + } + + $type = strtolower(gettype($value)); + + if ($type === 'double') { + $type = 'float'; + } + + if ($type === 'resource (closed)') { + $type = 'closed resource'; + } + + return match ($type) { + 'array', 'integer' => 'an ' . $type . ' ', + 'boolean', 'closed resource', 'float', 'resource', 'string' => 'a ' . $type . ' ', + 'null' => 'null ', + default => 'a value of ' . $type . ' ', + }; + } +} diff --git a/src/Framework/Constraint/Equality/IsEqual.php b/src/Framework/Constraint/Equality/IsEqual.php new file mode 100644 index 00000000000..2051bfce3e7 --- /dev/null +++ b/src/Framework/Constraint/Equality/IsEqual.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use SebastianBergmann\Comparator\ComparisonFailure; +use SebastianBergmann\Comparator\Factory as ComparatorFactory; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqual extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return true; + } + + $comparatorFactory = ComparatorFactory::getInstance(); + + try { + $comparator = $comparatorFactory->getComparatorFor( + $this->value, + $other, + ); + + $comparator->assertEquals( + $this->value, + $other, + ); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return false; + } + + throw new ExpectationFailedException( + trim($description . "\n" . $f->getMessage()), + $f, + ); + } + + return true; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $delta = ''; + + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + + return sprintf( + "is equal to '%s'", + $this->value, + ); + } + + return sprintf( + 'is equal to %s%s', + Exporter::export($this->value), + $delta, + ); + } +} diff --git a/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php b/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php new file mode 100644 index 00000000000..b826464db5c --- /dev/null +++ b/src/Framework/Constraint/Equality/IsEqualCanonicalizing.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use SebastianBergmann\Comparator\ComparisonFailure; +use SebastianBergmann\Comparator\Factory as ComparatorFactory; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualCanonicalizing extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return true; + } + + $comparatorFactory = ComparatorFactory::getInstance(); + + try { + $comparator = $comparatorFactory->getComparatorFor( + $this->value, + $other, + ); + + $comparator->assertEquals( + $this->value, + $other, + 0.0, + true, + ); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return false; + } + + throw new ExpectationFailedException( + trim($description . "\n" . $f->getMessage()), + $f, + ); + } + + return true; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + + return sprintf( + "is equal to '%s'", + $this->value, + ); + } + + return sprintf( + 'is equal to %s', + Exporter::export($this->value), + ); + } +} diff --git a/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php b/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php new file mode 100644 index 00000000000..c7b2c31da54 --- /dev/null +++ b/src/Framework/Constraint/Equality/IsEqualIgnoringCase.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function sprintf; +use function str_contains; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use SebastianBergmann\Comparator\ComparisonFailure; +use SebastianBergmann\Comparator\Factory as ComparatorFactory; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualIgnoringCase extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return true; + } + + $comparatorFactory = ComparatorFactory::getInstance(); + + try { + $comparator = $comparatorFactory->getComparatorFor( + $this->value, + $other, + ); + + $comparator->assertEquals( + $this->value, + $other, + 0.0, + false, + true, + ); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return false; + } + + throw new ExpectationFailedException( + trim($description . "\n" . $f->getMessage()), + $f, + ); + } + + return true; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_string($this->value)) { + if (str_contains($this->value, "\n")) { + return 'is equal to '; + } + + return sprintf( + "is equal to '%s'", + $this->value, + ); + } + + return sprintf( + 'is equal to %s', + Exporter::export($this->value), + ); + } +} diff --git a/src/Framework/Constraint/Equality/IsEqualWithDelta.php b/src/Framework/Constraint/Equality/IsEqualWithDelta.php new file mode 100644 index 00000000000..7f18b5bbee0 --- /dev/null +++ b/src/Framework/Constraint/Equality/IsEqualWithDelta.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use SebastianBergmann\Comparator\ComparisonFailure; +use SebastianBergmann\Comparator\Factory as ComparatorFactory; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsEqualWithDelta extends Constraint +{ + private readonly mixed $value; + private readonly float $delta; + + public function __construct(mixed $value, float $delta) + { + $this->value = $value; + $this->delta = $delta; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): bool + { + // If $this->value and $other are identical, they are also equal. + // This is the most common path and will allow us to skip + // initialization of all the comparators. + if ($this->value === $other) { + return true; + } + + $comparatorFactory = ComparatorFactory::getInstance(); + + try { + $comparator = $comparatorFactory->getComparatorFor( + $this->value, + $other, + ); + + $comparator->assertEquals( + $this->value, + $other, + $this->delta, + ); + } catch (ComparisonFailure $f) { + if ($returnResult) { + return false; + } + + throw new ExpectationFailedException( + trim($description . "\n" . $f->getMessage()), + $f, + ); + } + + return true; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'is equal to %s with delta <%F>', + Exporter::export($this->value), + $this->delta, + ); + } +} diff --git a/src/Framework/Constraint/Exception/Exception.php b/src/Framework/Constraint/Exception/Exception.php new file mode 100644 index 00000000000..a84f6eb988f --- /dev/null +++ b/src/Framework/Constraint/Exception/Exception.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use PHPUnit\Util\Filter; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends Constraint +{ + private readonly string $className; + + public function __construct(string $className) + { + $this->className = $className; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'exception of type "%s"', + $this->className, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other instanceof $this->className; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @throws \PHPUnit\Framework\Exception + */ + protected function failureDescription(mixed $other): string + { + if ($other === null) { + return sprintf( + 'exception of type "%s" is thrown', + $this->className, + ); + } + + $message = ''; + + if ($other instanceof Throwable) { + $message = '. Message was: "' . $other->getMessage() . '" at' + . "\n" . Filter::stackTraceFromThrowableAsString($other); + } + + return sprintf( + 'exception of type "%s" matches expected exception "%s"%s', + $other::class, + $this->className, + $message, + ); + } +} diff --git a/src/Framework/Constraint/Exception/ExceptionCode.php b/src/Framework/Constraint/Exception/ExceptionCode.php new file mode 100644 index 00000000000..666f733728f --- /dev/null +++ b/src/Framework/Constraint/Exception/ExceptionCode.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionCode extends Constraint +{ + private readonly int|string $expectedCode; + + public function __construct(int|string $expected) + { + $this->expectedCode = $expected; + } + + public function toString(): string + { + return 'exception code is ' . $this->expectedCode; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return (string) $other === (string) $this->expectedCode; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + '%s is equal to expected exception code %s', + Exporter::export($other), + Exporter::export($this->expectedCode), + ); + } +} diff --git a/src/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php b/src/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php new file mode 100644 index 00000000000..ae92090396c --- /dev/null +++ b/src/Framework/Constraint/Exception/ExceptionMessageIsOrContains.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function str_contains; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionMessageIsOrContains extends Constraint +{ + private readonly string $expectedMessage; + + public function __construct(string $expectedMessage) + { + $this->expectedMessage = $expectedMessage; + } + + public function toString(): string + { + if ($this->expectedMessage === '') { + return 'exception message is empty'; + } + + return 'exception message contains ' . Exporter::export($this->expectedMessage); + } + + protected function matches(mixed $other): bool + { + if ($this->expectedMessage === '') { + return $other === ''; + } + + return str_contains((string) $other, $this->expectedMessage); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if ($this->expectedMessage === '') { + return sprintf( + "exception message is empty but is '%s'", + $other, + ); + } + + return sprintf( + "exception message '%s' contains '%s'", + $other, + $this->expectedMessage, + ); + } +} diff --git a/src/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php b/src/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php new file mode 100644 index 00000000000..611af03746f --- /dev/null +++ b/src/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpression.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function preg_match; +use function sprintf; +use Exception; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExceptionMessageMatchesRegularExpression extends Constraint +{ + private readonly string $regularExpression; + + public function __construct(string $regularExpression) + { + $this->regularExpression = $regularExpression; + } + + public function toString(): string + { + return 'exception message matches ' . Exporter::export($this->regularExpression); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws \PHPUnit\Framework\Exception + * @throws Exception + */ + protected function matches(mixed $other): bool + { + $match = @preg_match($this->regularExpression, (string) $other); + + if ($match === false) { + throw new \PHPUnit\Framework\Exception( + sprintf( + 'Invalid expected exception message regular expression given: %s', + $this->regularExpression, + ), + ); + } + + return $match === 1; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + "exception message '%s' matches '%s'", + $other, + $this->regularExpression, + ); + } +} diff --git a/src/Framework/Constraint/Filesystem/DirectoryExists.php b/src/Framework/Constraint/Filesystem/DirectoryExists.php new file mode 100644 index 00000000000..83b991e1aee --- /dev/null +++ b/src/Framework/Constraint/Filesystem/DirectoryExists.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_dir; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class DirectoryExists extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'directory exists'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_dir($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + 'directory "%s" exists', + $other, + ); + } +} diff --git a/src/Framework/Constraint/Filesystem/FileExists.php b/src/Framework/Constraint/Filesystem/FileExists.php new file mode 100644 index 00000000000..cfc3b1b6f22 --- /dev/null +++ b/src/Framework/Constraint/Filesystem/FileExists.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function file_exists; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class FileExists extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'file exists'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return file_exists($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + 'file "%s" exists', + $other, + ); + } +} diff --git a/src/Framework/Constraint/Filesystem/IsReadable.php b/src/Framework/Constraint/Filesystem/IsReadable.php new file mode 100644 index 00000000000..1a32546ce7a --- /dev/null +++ b/src/Framework/Constraint/Filesystem/IsReadable.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_readable; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsReadable extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is readable'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_readable($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + '"%s" is readable', + $other, + ); + } +} diff --git a/src/Framework/Constraint/Filesystem/IsWritable.php b/src/Framework/Constraint/Filesystem/IsWritable.php new file mode 100644 index 00000000000..24e94f821df --- /dev/null +++ b/src/Framework/Constraint/Filesystem/IsWritable.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_writable; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsWritable extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is writable'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_writable($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + '"%s" is writable', + $other, + ); + } +} diff --git a/src/Framework/Constraint/IsAnything.php b/src/Framework/Constraint/IsAnything.php new file mode 100644 index 00000000000..d65844fc586 --- /dev/null +++ b/src/Framework/Constraint/IsAnything.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsAnything extends Constraint +{ + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws void + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): ?bool + { + return $returnResult ? true : null; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is anything'; + } + + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return 0; + } +} diff --git a/src/Framework/Constraint/IsIdentical.php b/src/Framework/Constraint/IsIdentical.php new file mode 100644 index 00000000000..03ba16f7777 --- /dev/null +++ b/src/Framework/Constraint/IsIdentical.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function explode; +use function gettype; +use function is_array; +use function is_object; +use function is_string; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\Exporter; +use SebastianBergmann\Comparator\ComparisonFailure; +use UnitEnum; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsIdentical extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): ?bool + { + $success = $this->value === $other; + + if ($returnResult) { + return $success; + } + + if (!$success) { + $f = null; + + // if both values are strings, make sure a diff is generated + if (is_string($this->value) && is_string($other)) { + $f = new ComparisonFailure( + $this->value, + $other, + sprintf("'%s'", $this->value), + sprintf("'%s'", $other), + ); + } + + // if both values are array or enums, make sure a diff is generated + if ((is_array($this->value) && is_array($other)) || ($this->value instanceof UnitEnum && $other instanceof UnitEnum)) { + $f = new ComparisonFailure( + $this->value, + $other, + Exporter::export($this->value), + Exporter::export($other), + ); + } + + $this->fail($other, $description, $f); + } + + return null; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + if (is_object($this->value)) { + return 'is identical to an object of class "' . + $this->value::class . '"'; + } + + return 'is identical to ' . Exporter::export($this->value); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if (is_object($this->value) && is_object($other)) { + return 'two variables reference the same object'; + } + + if (explode(' ', gettype($this->value), 2)[0] === 'resource' && explode(' ', gettype($other), 2)[0] === 'resource') { + return 'two variables reference the same resource'; + } + + if (is_string($this->value) && is_string($other)) { + return 'two strings are identical'; + } + + if (is_array($this->value) && is_array($other)) { + return 'two arrays are identical'; + } + + return parent::failureDescription($other); + } +} diff --git a/src/Framework/Constraint/JsonMatches.php b/src/Framework/Constraint/JsonMatches.php new file mode 100644 index 00000000000..3fd6736a43c --- /dev/null +++ b/src/Framework/Constraint/JsonMatches.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function json_decode; +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Util\InvalidJsonException; +use PHPUnit\Util\Json; +use SebastianBergmann\Comparator\ComparisonFailure; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class JsonMatches extends Constraint +{ + private readonly string $value; + + public function __construct(string $value) + { + $this->value = $value; + } + + /** + * Returns a string representation of the object. + */ + public function toString(): string + { + return sprintf( + 'matches JSON string "%s"', + $this->value, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * This method can be overridden to implement the evaluation algorithm. + */ + protected function matches(mixed $other): bool + { + [$error, $recodedOther] = Json::canonicalize($other); + + if ($error) { + return false; + } + + [$error, $recodedValue] = Json::canonicalize($this->value); + + if ($error) { + return false; + } + + return $recodedOther === $recodedValue; + } + + /** + * Throws an exception for the given compared value and test description. + * + * @throws ExpectationFailedException + * @throws InvalidJsonException + */ + protected function fail(mixed $other, string $description, ?ComparisonFailure $comparisonFailure = null): never + { + if ($comparisonFailure === null) { + [$error, $recodedOther] = Json::canonicalize($other); + + if ($error) { + parent::fail($other, $description); + } + + [$error, $recodedValue] = Json::canonicalize($this->value); + + if ($error) { + parent::fail($other, $description); + } + + $comparisonFailure = new ComparisonFailure( + json_decode($this->value), + json_decode($other), + Json::prettify($recodedValue), + Json::prettify($recodedOther), + 'Failed asserting that two json values are equal.', + ); + } + + parent::fail($other, $description, $comparisonFailure); + } +} diff --git a/src/Framework/Constraint/Math/IsFinite.php b/src/Framework/Constraint/Math/IsFinite.php new file mode 100644 index 00000000000..b70de503d31 --- /dev/null +++ b/src/Framework/Constraint/Math/IsFinite.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_finite; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsFinite extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is finite'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_finite($other); + } +} diff --git a/src/Framework/Constraint/Math/IsInfinite.php b/src/Framework/Constraint/Math/IsInfinite.php new file mode 100644 index 00000000000..dbf4803bc57 --- /dev/null +++ b/src/Framework/Constraint/Math/IsInfinite.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_infinite; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsInfinite extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is infinite'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_infinite($other); + } +} diff --git a/src/Framework/Constraint/Math/IsNan.php b/src/Framework/Constraint/Math/IsNan.php new file mode 100644 index 00000000000..f9c47219e60 --- /dev/null +++ b/src/Framework/Constraint/Math/IsNan.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_nan; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsNan extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is nan'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return is_nan($other); + } +} diff --git a/src/Framework/Constraint/Object/ObjectEquals.php b/src/Framework/Constraint/Object/ObjectEquals.php new file mode 100644 index 00000000000..2c78ea42759 --- /dev/null +++ b/src/Framework/Constraint/Object/ObjectEquals.php @@ -0,0 +1,146 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function assert; +use function count; +use function is_object; +use PHPUnit\Framework\ActualValueIsNotAnObjectException; +use PHPUnit\Framework\ComparisonMethodDoesNotAcceptParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareBoolReturnTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareExactlyOneParameterException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotExistException; +use ReflectionNamedType; +use ReflectionObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ObjectEquals extends Constraint +{ + private readonly object $expected; + private readonly string $method; + + public function __construct(object $object, string $method = 'equals') + { + $this->expected = $object; + $this->method = $method; + } + + public function toString(): string + { + return 'two objects are equal'; + } + + /** + * @throws ActualValueIsNotAnObjectException + * @throws ComparisonMethodDoesNotAcceptParameterTypeException + * @throws ComparisonMethodDoesNotDeclareBoolReturnTypeException + * @throws ComparisonMethodDoesNotDeclareExactlyOneParameterException + * @throws ComparisonMethodDoesNotDeclareParameterTypeException + * @throws ComparisonMethodDoesNotExistException + */ + protected function matches(mixed $other): bool + { + if (!is_object($other)) { + throw new ActualValueIsNotAnObjectException; + } + + $object = new ReflectionObject($other); + + if (!$object->hasMethod($this->method)) { + throw new ComparisonMethodDoesNotExistException( + $other::class, + $this->method, + ); + } + + $method = $object->getMethod($this->method); + + if (!$method->hasReturnType()) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + $other::class, + $this->method, + ); + } + + $returnType = $method->getReturnType(); + + if (!$returnType instanceof ReflectionNamedType) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + $other::class, + $this->method, + ); + } + + if ($returnType->allowsNull()) { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + $other::class, + $this->method, + ); + } + + if ($returnType->getName() !== 'bool') { + throw new ComparisonMethodDoesNotDeclareBoolReturnTypeException( + $other::class, + $this->method, + ); + } + + if ($method->getNumberOfParameters() !== 1 || $method->getNumberOfRequiredParameters() !== 1) { + throw new ComparisonMethodDoesNotDeclareExactlyOneParameterException( + $other::class, + $this->method, + ); + } + + assert(count($method->getParameters()) > 0); + $parameter = $method->getParameters()[0]; + + if (!$parameter->hasType()) { + throw new ComparisonMethodDoesNotDeclareParameterTypeException( + $other::class, + $this->method, + ); + } + + $type = $parameter->getType(); + + if (!$type instanceof ReflectionNamedType) { + throw new ComparisonMethodDoesNotDeclareParameterTypeException( + $other::class, + $this->method, + ); + } + + $typeName = $type->getName(); + + if ($typeName === 'self') { + $typeName = $other::class; + } + + if (!$this->expected instanceof $typeName) { + throw new ComparisonMethodDoesNotAcceptParameterTypeException( + $other::class, + $this->method, + $this->expected::class, + ); + } + + /** @phpstan-ignore method.dynamicName */ + return $other->{$this->method}($this->expected); + } + + protected function failureDescription(mixed $other): string + { + return $this->toString(); + } +} diff --git a/src/Framework/Constraint/Object/ObjectHasProperty.php b/src/Framework/Constraint/Object/ObjectHasProperty.php new file mode 100644 index 00000000000..39e4680d9f3 --- /dev/null +++ b/src/Framework/Constraint/Object/ObjectHasProperty.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function gettype; +use function is_object; +use function sprintf; +use ReflectionObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ObjectHasProperty extends Constraint +{ + private readonly string $propertyName; + + public function __construct(string $propertyName) + { + $this->propertyName = $propertyName; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'has property "%s"', + $this->propertyName, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @param mixed $other value or object to evaluate + */ + protected function matches(mixed $other): bool + { + if (!is_object($other)) { + return false; + } + + return new ReflectionObject($other)->hasProperty($this->propertyName); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + * + * @param mixed $other evaluated value or object + */ + protected function failureDescription(mixed $other): string + { + if (is_object($other)) { + return sprintf( + 'object of class "%s" %s', + $other::class, + $this->toString(), + ); + } + + return sprintf( + '"%s" (%s) %s', + $other, + gettype($other), + $this->toString(), + ); + } +} diff --git a/src/Framework/Constraint/Operator/BinaryOperator.php b/src/Framework/Constraint/Operator/BinaryOperator.php new file mode 100644 index 00000000000..feb6d040899 --- /dev/null +++ b/src/Framework/Constraint/Operator/BinaryOperator.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_map; +use function count; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class BinaryOperator extends Operator +{ + /** + * @var list + */ + private readonly array $constraints; + + protected function __construct(mixed ...$constraints) + { + $this->constraints = array_map( + fn (mixed $constraint): Constraint => $this->checkConstraint($constraint), + $constraints, + ); + } + + /** + * Returns the number of operands (constraints). + */ + final public function arity(): int + { + return count($this->constraints); + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $reduced = $this->reduce(); + + if ($reduced !== $this) { + return $reduced->toString(); + } + + $text = ''; + + foreach ($this->constraints as $key => $constraint) { + $constraint = $constraint->reduce(); + + $text .= $this->constraintToString($constraint, $key); + } + + return $text; + } + + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + $count = 0; + + foreach ($this->constraints as $constraint) { + $count += count($constraint); + } + + return $count; + } + + /** + * @return list + */ + final protected function constraints(): array + { + return $this->constraints; + } + + /** + * Returns true if the $constraint needs to be wrapped with braces. + */ + final protected function constraintNeedsParentheses(Constraint $constraint): bool + { + return $this->arity() > 1 && parent::constraintNeedsParentheses($constraint); + } + + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * See Constraint::reduce() for more. + */ + protected function reduce(): Constraint + { + if (count($this->constraints) === 1 && $this->constraints[0] instanceof Operator) { + return $this->constraints[0]->reduce(); + } + + return parent::reduce(); + } + + /** + * Returns string representation of given operand in context of this operator. + */ + private function constraintToString(Constraint $constraint, int $position): string + { + $prefix = ''; + + if ($position > 0) { + $prefix = (' ' . $this->operator() . ' '); + } + + if ($this->constraintNeedsParentheses($constraint)) { + return $prefix . '( ' . $constraint->toString() . ' )'; + } + + $string = $constraint->toStringInContext($this, $position); + + if ($string === '') { + $string = $constraint->toString(); + } + + return $prefix . $string; + } +} diff --git a/src/Framework/Constraint/Operator/LogicalAnd.php b/src/Framework/Constraint/Operator/LogicalAnd.php new file mode 100644 index 00000000000..e0a00a0ea4c --- /dev/null +++ b/src/Framework/Constraint/Operator/LogicalAnd.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalAnd extends BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'and'; + } + + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 22; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + foreach ($this->constraints() as $constraint) { + if (!$constraint->evaluate($other, '', true)) { + return false; + } + } + + return [] !== $this->constraints(); + } +} diff --git a/src/Framework/Constraint/Operator/LogicalNot.php b/src/Framework/Constraint/Operator/LogicalNot.php new file mode 100644 index 00000000000..224260909f2 --- /dev/null +++ b/src/Framework/Constraint/Operator/LogicalNot.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_map; +use function count; +use function preg_match; +use function preg_quote; +use function preg_replace; +use PHPUnit\Framework\ExpectationFailedException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalNot extends UnaryOperator +{ + public static function negate(string $string): string + { + $positives = [ + 'contains ', + 'exists', + 'has ', + 'is ', + 'are ', + 'matches ', + 'starts with ', + 'ends with ', + 'reference ', + 'not not ', + ]; + + $negatives = [ + 'does not contain ', + 'does not exist', + 'does not have ', + 'is not ', + 'are not ', + 'does not match ', + 'starts not with ', + 'ends not with ', + 'don\'t reference ', + 'not ', + ]; + + preg_match('/(\'[\w\W]*\')([\w\W]*)("[\w\W]*")/i', $string, $matches); + + if (count($matches) === 0) { + preg_match('/(\'[\w\W]*\')([\w\W]*)(\'[\w\W]*\')/i', $string, $matches); + } + + $positives = array_map( + static fn (string $s) => '/\\b' . preg_quote($s, '/') . '/', + $positives, + ); + + if (count($matches) >= 3) { + $nonInput = $matches[2]; + + $negatedString = preg_replace( + '/' . preg_quote($nonInput, '/') . '/', + preg_replace( + $positives, + $negatives, + $nonInput, + ), + $string, + ); + } else { + $negatedString = preg_replace( + $positives, + $negatives, + $string, + ); + } + + return $negatedString; + } + + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'not'; + } + + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 5; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws ExpectationFailedException + */ + protected function matches(mixed $other): bool + { + return !$this->constraint()->evaluate($other, '', true); + } + + /** + * Applies additional transformation to strings returned by toString() or + * failureDescription(). + */ + protected function transformString(string $string): string + { + return self::negate($string); + } + + /** + * Reduces the sub-expression starting at $this by skipping degenerate + * sub-expression and returns first descendant constraint that starts + * a non-reducible sub-expression. + * + * See Constraint::reduce() for more. + */ + protected function reduce(): Constraint + { + $constraint = $this->constraint(); + + if ($constraint instanceof self) { + return $constraint->constraint()->reduce(); + } + + return parent::reduce(); + } +} diff --git a/src/Framework/Constraint/Operator/LogicalOr.php b/src/Framework/Constraint/Operator/LogicalOr.php new file mode 100644 index 00000000000..370aa2cab78 --- /dev/null +++ b/src/Framework/Constraint/Operator/LogicalOr.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_any; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalOr extends BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'or'; + } + + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + public function precedence(): int + { + return 24; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + public function matches(mixed $other): bool + { + return array_any( + $this->constraints(), + static fn (Constraint $constraint) => $constraint->evaluate($other, '', true), + ); + } +} diff --git a/src/Framework/Constraint/Operator/LogicalXor.php b/src/Framework/Constraint/Operator/LogicalXor.php new file mode 100644 index 00000000000..3b40a126190 --- /dev/null +++ b/src/Framework/Constraint/Operator/LogicalXor.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_reduce; +use function array_shift; +use PHPUnit\Framework\ExpectationFailedException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class LogicalXor extends BinaryOperator +{ + public static function fromConstraints(mixed ...$constraints): self + { + return new self(...$constraints); + } + + /** + * Returns the name of this operator. + */ + public function operator(): string + { + return 'xor'; + } + + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php. + */ + public function precedence(): int + { + return 23; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + * + * @throws ExpectationFailedException + */ + public function matches(mixed $other): bool + { + $constraints = $this->constraints(); + + $initial = array_shift($constraints); + + if ($initial === null) { + return false; + } + + return array_reduce( + $constraints, + static fn (?bool $matches, Constraint $constraint): bool => $matches xor $constraint->evaluate($other, '', true), + $initial->evaluate($other, '', true), + ); + } +} diff --git a/src/Framework/Constraint/Operator/Operator.php b/src/Framework/Constraint/Operator/Operator.php new file mode 100644 index 00000000000..1195156e036 --- /dev/null +++ b/src/Framework/Constraint/Operator/Operator.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class Operator extends Constraint +{ + /** + * Returns the name of this operator. + */ + abstract public function operator(): string; + + /** + * Returns this operator's precedence. + * + * @see https://www.php.net/manual/en/language.operators.precedence.php + */ + abstract public function precedence(): int; + + /** + * Returns the number of operands. + */ + abstract public function arity(): int; + + /** + * Validates $constraint argument. + */ + protected function checkConstraint(mixed $constraint): Constraint + { + if (!$constraint instanceof Constraint) { + return new IsEqual($constraint); + } + + return $constraint; + } + + /** + * Returns true if the $constraint needs to be wrapped with braces. + */ + protected function constraintNeedsParentheses(Constraint $constraint): bool + { + return $constraint instanceof self && + $constraint->arity() > 1 && + $this->precedence() <= $constraint->precedence(); + } +} diff --git a/src/Framework/Constraint/Operator/UnaryOperator.php b/src/Framework/Constraint/Operator/UnaryOperator.php new file mode 100644 index 00000000000..d6ac6e3f6c8 --- /dev/null +++ b/src/Framework/Constraint/Operator/UnaryOperator.php @@ -0,0 +1,128 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function count; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class UnaryOperator extends Operator +{ + private readonly Constraint $constraint; + + public function __construct(mixed $constraint) + { + $this->constraint = $this->checkConstraint($constraint); + } + + /** + * Returns the number of operands (constraints). + */ + public function arity(): int + { + return 1; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $reduced = $this->reduce(); + + if ($reduced !== $this) { + return $reduced->toString(); + } + + $constraint = $this->constraint->reduce(); + + if ($this->constraintNeedsParentheses($constraint)) { + return $this->operator() . '( ' . $constraint->toString() . ' )'; + } + + $string = $constraint->toStringInContext($this, 0); + + if ($string === '') { + return $this->transformString($constraint->toString()); + } + + return $string; + } + + /** + * Counts the number of constraint elements. + */ + public function count(): int + { + return count($this->constraint); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + $reduced = $this->reduce(); + + if ($reduced !== $this) { + return $reduced->failureDescription($other); + } + + $constraint = $this->constraint->reduce(); + + if ($this->constraintNeedsParentheses($constraint)) { + return $this->operator() . '( ' . $constraint->failureDescription($other) . ' )'; + } + + $string = $constraint->failureDescriptionInContext($this, 0, $other); + + if ($string === '') { + return $this->transformString($constraint->failureDescription($other)); + } + + return $string; + } + + /** + * Transforms string returned by the member constraint's toString() or + * failureDescription() such that it reflects constraint's participation in + * this expression. + * + * The method may be overwritten in a subclass to apply default + * transformation in case the operand constraint does not provide its own + * custom strings via toStringInContext() or failureDescriptionInContext(). + */ + protected function transformString(string $string): string + { + return $string; + } + + /** + * Provides access to $this->constraint for subclasses. + */ + final protected function constraint(): Constraint + { + return $this->constraint; + } + + /** + * Returns true if the $constraint needs to be wrapped with parentheses. + */ + protected function constraintNeedsParentheses(Constraint $constraint): bool + { + $constraint = $constraint->reduce(); + + return $constraint instanceof self || parent::constraintNeedsParentheses($constraint); + } +} diff --git a/src/Framework/Constraint/String/IsJson.php b/src/Framework/Constraint/String/IsJson.php new file mode 100644 index 00000000000..582b58e8bdc --- /dev/null +++ b/src/Framework/Constraint/String/IsJson.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const JSON_ERROR_CTRL_CHAR; +use const JSON_ERROR_DEPTH; +use const JSON_ERROR_NONE; +use const JSON_ERROR_STATE_MISMATCH; +use const JSON_ERROR_SYNTAX; +use const JSON_ERROR_UTF8; +use function is_string; +use function json_decode; +use function json_last_error; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsJson extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is valid JSON'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (!is_string($other) || $other === '') { + return false; + } + + json_decode($other); + + if (json_last_error() !== JSON_ERROR_NONE) { + return false; + } + + return true; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + if (!is_string($other)) { + return $this->valueToTypeStringFragment($other) . 'is valid JSON'; + } + + if ($other === '') { + return 'an empty string is valid JSON'; + } + + return sprintf( + 'a string is valid JSON (%s)', + $this->determineJsonError($other), + ); + } + + private function determineJsonError(string $json): string + { + json_decode($json); + + return match (json_last_error()) { + JSON_ERROR_NONE => '', + JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', + JSON_ERROR_STATE_MISMATCH => 'Underflow or the modes mismatch', + JSON_ERROR_CTRL_CHAR => 'Unexpected control character found', + JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON', + JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded', + default => 'Unknown error', + }; + } +} diff --git a/src/Framework/Constraint/String/RegularExpression.php b/src/Framework/Constraint/String/RegularExpression.php new file mode 100644 index 00000000000..03b0e4ea1a3 --- /dev/null +++ b/src/Framework/Constraint/String/RegularExpression.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function preg_match; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class RegularExpression extends Constraint +{ + private readonly string $pattern; + + public function __construct(string $pattern) + { + $this->pattern = $pattern; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'matches PCRE pattern "%s"', + $this->pattern, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return preg_match($this->pattern, $other) > 0; + } +} diff --git a/src/Framework/Constraint/String/StringContains.php b/src/Framework/Constraint/String/StringContains.php new file mode 100644 index 00000000000..0f801a605fd --- /dev/null +++ b/src/Framework/Constraint/String/StringContains.php @@ -0,0 +1,160 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_string; +use function mb_detect_encoding; +use function mb_stripos; +use function mb_strtolower; +use function sprintf; +use function str_contains; +use function strlen; +use function strtr; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringContains extends Constraint +{ + private readonly string $needle; + private readonly bool $ignoreCase; + private readonly bool $ignoreLineEndings; + + public function __construct(string $needle, bool $ignoreCase = false, bool $ignoreLineEndings = false) + { + if ($ignoreLineEndings) { + $needle = $this->normalizeLineEndings($needle); + } + + $this->needle = $needle; + $this->ignoreCase = $ignoreCase; + $this->ignoreLineEndings = $ignoreLineEndings; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + $needle = $this->needle; + + if ($this->ignoreCase) { + $needle = mb_strtolower($this->needle, 'UTF-8'); + } + + return sprintf( + 'contains "%s" [%s](length: %s)', + $needle, + $this->detectedEncoding($needle), + strlen($needle), + ); + } + + public function failureDescription(mixed $other): string + { + $stringifiedHaystack = Exporter::export($other); + $haystackEncoding = $this->detectedEncoding($other); + $haystackLength = $this->haystackLength($other); + + $haystackInformation = sprintf( + '%s [%s](length: %s) ', + $stringifiedHaystack, + $haystackEncoding, + $haystackLength, + ); + + $needleInformation = $this->toString(); + + return $haystackInformation . $needleInformation; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + $haystack = $other; + + if ('' === $this->needle) { + return true; + } + + if (!is_string($haystack)) { + return false; + } + + if ($this->ignoreLineEndings) { + $haystack = $this->normalizeLineEndings($haystack); + } + + if ($this->ignoreCase) { + /* + * We must use the multibyte-safe version, so we can accurately compare non-latin uppercase characters with + * their lowercase equivalents. + */ + return mb_stripos($haystack, $this->needle, 0, 'UTF-8') !== false; + } + + /* + * Use the non-multibyte safe functions to see if the string is contained in $other. + * + * This function is very fast, and we don't care about the character position in the string. + * + * Additionally, we want this method to be binary safe, so we can check if some binary data is in other binary + * data. + */ + return str_contains($haystack, $this->needle); + } + + private function detectedEncoding(mixed $other): string + { + if ($this->ignoreCase) { + return 'Encoding ignored'; + } + + if (!is_string($other)) { + return 'Encoding detection failed'; + } + + $detectedEncoding = mb_detect_encoding($other, null, true); + + if ($detectedEncoding === false) { + return 'Encoding detection failed'; + } + + return $detectedEncoding; + } + + private function haystackLength(mixed $haystack): int + { + if (!is_string($haystack)) { + return 0; + } + + if ($this->ignoreLineEndings) { + $haystack = $this->normalizeLineEndings($haystack); + } + + return strlen($haystack); + } + + private function normalizeLineEndings(string $string): string + { + return strtr( + $string, + [ + "\r\n" => "\n", + "\r" => "\n", + ], + ); + } +} diff --git a/src/Framework/Constraint/String/StringEndsWith.php b/src/Framework/Constraint/String/StringEndsWith.php new file mode 100644 index 00000000000..1dd43b84b74 --- /dev/null +++ b/src/Framework/Constraint/String/StringEndsWith.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function str_ends_with; +use PHPUnit\Framework\EmptyStringException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringEndsWith extends Constraint +{ + private readonly string $suffix; + + /** + * @throws EmptyStringException + */ + public function __construct(string $suffix) + { + if ($suffix === '') { + throw new EmptyStringException; + } + + $this->suffix = $suffix; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'ends with "' . $this->suffix . '"'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return str_ends_with((string) $other, $this->suffix); + } +} diff --git a/src/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php b/src/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php new file mode 100644 index 00000000000..56c59943ef2 --- /dev/null +++ b/src/Framework/Constraint/String/StringEqualsStringIgnoringLineEndings.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function sprintf; +use function strtr; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringEqualsStringIgnoringLineEndings extends Constraint +{ + private readonly string $string; + + public function __construct(string $string) + { + $this->string = $this->normalizeLineEndings($string); + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'is equal to "%s" ignoring line endings', + $this->string, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $this->string === $this->normalizeLineEndings((string) $other); + } + + private function normalizeLineEndings(string $string): string + { + return strtr( + $string, + [ + "\r\n" => "\n", + "\r" => "\n", + ], + ); + } +} diff --git a/src/Framework/Constraint/String/StringMatchesFormatDescription.php b/src/Framework/Constraint/String/StringMatchesFormatDescription.php new file mode 100644 index 00000000000..4df81715f82 --- /dev/null +++ b/src/Framework/Constraint/String/StringMatchesFormatDescription.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function explode; +use function implode; +use function preg_match; +use function preg_quote; +use function preg_replace; +use function strtr; +use SebastianBergmann\Diff\Differ; +use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringMatchesFormatDescription extends Constraint +{ + private readonly string $formatDescription; + + public function __construct(string $formatDescription) + { + $this->formatDescription = $formatDescription; + } + + public function toString(): string + { + return 'matches format description:' . PHP_EOL . $this->formatDescription; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + $other = $this->convertNewlines($other); + + $matches = preg_match( + $this->regularExpressionForFormatDescription( + $this->convertNewlines($this->formatDescription), + ), + $other, + ); + + return $matches > 0; + } + + protected function failureDescription(mixed $other): string + { + return 'string matches format description'; + } + + /** + * Returns a cleaned up diff. + * + * The expected string can contain placeholders like %s and %d. + * By using 'diff' such placeholders compared to the real output will + * always be different, although we don't want to show them as different. + * This method removes the expected differences by figuring out if a difference + * is allowed by the use of a placeholder. + * + * The problem here are %A and %a multiline placeholders since we look at the + * expected and actual output line by line. If differences allowed by those placeholders + * stretch over multiple lines they will still end up in the final diff. + * And since they mess up the line sync between the expected and actual output + * all following allowed changes will not be detected/removed anymore. + */ + protected function additionalFailureDescription(mixed $other): string + { + $from = explode("\n", $this->formatDescription); + $to = explode("\n", $this->convertNewlines($other)); + + foreach ($from as $index => $line) { + // is the expected output line different from the actual output line + if (isset($to[$index]) && $line !== $to[$index]) { + $line = $this->regularExpressionForFormatDescription($line); + + // if the difference is allowed by a placeholder + // overwrite the expected line with the actual line to prevent it from showing up in the diff + if (preg_match($line, $to[$index]) > 0) { + $from[$index] = $to[$index]; + } + } + } + + $from = implode("\n", $from); + $to = implode("\n", $to); + + return $this->differ()->diff($from, $to); + } + + private function regularExpressionForFormatDescription(string $string): string + { + $string = strtr( + preg_quote($string, '/'), + [ + '%%' => '%', + '%e' => preg_quote(DIRECTORY_SEPARATOR, '/'), + '%s' => '[^\r\n]+', + '%S' => '[^\r\n]*', + '%a' => '.+?', + '%A' => '.*?', + '%w' => '\s*', + '%i' => '[+-]?\d+', + '%d' => '\d+', + '%x' => '[0-9a-fA-F]+', + '%f' => '[+-]?(?:\d+|(?=\.\d))(?:\.\d+)?(?:[Ee][+-]?\d+)?', + '%c' => '.', + '%0' => '\x00', + ], + ); + + return '/^' . $string . '$/s'; + } + + private function convertNewlines(string $text): string + { + return preg_replace('/\r\n/', "\n", $text); + } + + private function differ(): Differ + { + return new Differ(new UnifiedDiffOutputBuilder("--- Expected\n+++ Actual\n")); + } +} diff --git a/src/Framework/Constraint/String/StringStartsWith.php b/src/Framework/Constraint/String/StringStartsWith.php new file mode 100644 index 00000000000..eee545c7811 --- /dev/null +++ b/src/Framework/Constraint/String/StringStartsWith.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function str_starts_with; +use PHPUnit\Framework\EmptyStringException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class StringStartsWith extends Constraint +{ + private readonly string $prefix; + + /** + * @throws EmptyStringException + */ + public function __construct(string $prefix) + { + if ($prefix === '') { + throw new EmptyStringException; + } + + $this->prefix = $prefix; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'starts with "' . $this->prefix . '"'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return str_starts_with((string) $other, $this->prefix); + } +} diff --git a/src/Framework/Constraint/Traversable/ArrayHasKey.php b/src/Framework/Constraint/Traversable/ArrayHasKey.php new file mode 100644 index 00000000000..fa8d2744111 --- /dev/null +++ b/src/Framework/Constraint/Traversable/ArrayHasKey.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_key_exists; +use function is_array; +use ArrayAccess; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ArrayHasKey extends Constraint +{ + private readonly mixed $key; + + public function __construct(mixed $key) + { + $this->key = $key; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'has the key ' . Exporter::export($this->key); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (is_array($other)) { + return array_key_exists($this->key, $other); + } + + if ($other instanceof ArrayAccess) { + return $other->offsetExists($this->key); + } + + return false; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return 'an array ' . $this->toString(); + } +} diff --git a/src/Framework/Constraint/Traversable/IsList.php b/src/Framework/Constraint/Traversable/IsList.php new file mode 100644 index 00000000000..f6ac30618e0 --- /dev/null +++ b/src/Framework/Constraint/Traversable/IsList.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function array_is_list; +use function is_array; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsList extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is a list'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if (!is_array($other)) { + return false; + } + + return array_is_list($other); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return $this->valueToTypeStringFragment($other) . $this->toString(); + } +} diff --git a/src/Framework/Constraint/Traversable/TraversableContains.php b/src/Framework/Constraint/Traversable/TraversableContains.php new file mode 100644 index 00000000000..6f1a298bf1a --- /dev/null +++ b/src/Framework/Constraint/Traversable/TraversableContains.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function is_array; +use function sprintf; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TraversableContains extends Constraint +{ + private readonly mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'contains ' . Exporter::export($this->value); + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return sprintf( + '%s %s', + is_array($other) ? 'an array' : 'a traversable', + $this->toString(), + ); + } + + protected function value(): mixed + { + return $this->value; + } +} diff --git a/src/Framework/Constraint/Traversable/TraversableContainsEqual.php b/src/Framework/Constraint/Traversable/TraversableContainsEqual.php new file mode 100644 index 00000000000..f89835163c5 --- /dev/null +++ b/src/Framework/Constraint/Traversable/TraversableContainsEqual.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use SplObjectStorage; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsEqual extends TraversableContains +{ + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof SplObjectStorage) { + return $other->offsetExists($this->value()); + } + + foreach ($other as $element) { + /** @phpstan-ignore equal.notAllowed */ + if ($this->value() == $element) { + return true; + } + } + + return false; + } +} diff --git a/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php b/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php new file mode 100644 index 00000000000..b4e295376bf --- /dev/null +++ b/src/Framework/Constraint/Traversable/TraversableContainsIdentical.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use SplObjectStorage; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsIdentical extends TraversableContains +{ + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + if ($other instanceof SplObjectStorage) { + return $other->offsetExists($this->value()); + } + + foreach ($other as $element) { + if ($this->value() === $element) { + return true; + } + } + + return false; + } +} diff --git a/src/Framework/Constraint/Traversable/TraversableContainsOnly.php b/src/Framework/Constraint/Traversable/TraversableContainsOnly.php new file mode 100644 index 00000000000..50da87f298d --- /dev/null +++ b/src/Framework/Constraint/Traversable/TraversableContainsOnly.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\NativeType; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TraversableContainsOnly extends Constraint +{ + private readonly Constraint $constraint; + private readonly string $type; + + public static function forNativeType(NativeType $type): self + { + return new self(new IsType($type), $type->value); + } + + /** + * @param class-string $type + */ + public static function forClassOrInterface(string $type): self + { + return new self(new IsInstanceOf($type), $type); + } + + private function __construct(IsInstanceOf|IsType $constraint, string $type) + { + $this->constraint = $constraint; + $this->type = $type; + } + + /** + * Evaluates the constraint for parameter $other. + * + * If $returnResult is set to false (the default), an exception is thrown + * in case of a failure. null is returned otherwise. + * + * If $returnResult is true, the result of the evaluation is returned as + * a boolean value instead: true in case of success, false in case of a + * failure. + * + * @throws ExpectationFailedException + */ + public function evaluate(mixed $other, string $description = '', bool $returnResult = false): bool + { + $success = true; + + foreach ($other as $item) { + if (!$this->constraint->evaluate($item, '', true)) { + $success = false; + + break; + } + } + + if (!$success && !$returnResult) { + $this->fail($other, $description); + } + + return $success; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'contains only values of type "' . $this->type . '"'; + } +} diff --git a/src/Framework/Constraint/Type/IsInstanceOf.php b/src/Framework/Constraint/Type/IsInstanceOf.php new file mode 100644 index 00000000000..df7ebf1e2c3 --- /dev/null +++ b/src/Framework/Constraint/Type/IsInstanceOf.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function class_exists; +use function interface_exists; +use function sprintf; +use PHPUnit\Framework\UnknownClassOrInterfaceException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsInstanceOf extends Constraint +{ + /** + * @var class-string + */ + private readonly string $name; + + /** + * @var 'class'|'interface' + */ + private readonly string $type; + + /** + * @throws UnknownClassOrInterfaceException + */ + public function __construct(string $name) + { + if (class_exists($name)) { + $this->type = 'class'; + } elseif (interface_exists($name)) { + $this->type = 'interface'; + } else { + throw new UnknownClassOrInterfaceException($name); + } + + $this->name = $name; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'is an instance of %s %s', + $this->type, + $this->name, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other instanceof $this->name; + } + + /** + * Returns the description of the failure. + * + * The beginning of failure messages is "Failed asserting that" in most + * cases. This method should return the second part of that sentence. + */ + protected function failureDescription(mixed $other): string + { + return $this->valueToTypeStringFragment($other) . $this->toString(); + } +} diff --git a/src/Framework/Constraint/Type/IsNull.php b/src/Framework/Constraint/Type/IsNull.php new file mode 100644 index 00000000000..37c89f7a043 --- /dev/null +++ b/src/Framework/Constraint/Type/IsNull.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsNull extends Constraint +{ + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return 'is null'; + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + return $other === null; + } +} diff --git a/src/Framework/Constraint/Type/IsType.php b/src/Framework/Constraint/Type/IsType.php new file mode 100644 index 00000000000..c2bff8eda98 --- /dev/null +++ b/src/Framework/Constraint/Type/IsType.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function gettype; +use function is_array; +use function is_bool; +use function is_callable; +use function is_float; +use function is_int; +use function is_iterable; +use function is_numeric; +use function is_object; +use function is_scalar; +use function is_string; +use function sprintf; +use PHPUnit\Framework\NativeType; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class IsType extends Constraint +{ + private readonly NativeType $type; + + public function __construct(NativeType $type) + { + $this->type = $type; + } + + /** + * Returns a string representation of the constraint. + */ + public function toString(): string + { + return sprintf( + 'is of type %s', + $this->type->value, + ); + } + + /** + * Evaluates the constraint for parameter $other. Returns true if the + * constraint is met, false otherwise. + */ + protected function matches(mixed $other): bool + { + switch ($this->type) { + case NativeType::Numeric: + return is_numeric($other); + + case NativeType::Int: + return is_int($other); + + case NativeType::Float: + return is_float($other); + + case NativeType::String: + return is_string($other); + + case NativeType::Bool: + return is_bool($other); + + case NativeType::Null: + return null === $other; + + case NativeType::Array: + return is_array($other); + + case NativeType::Object: + return is_object($other); + + case NativeType::Resource: + $type = gettype($other); + + return $type === 'resource' || $type === 'resource (closed)'; + + case NativeType::ClosedResource: + return gettype($other) === 'resource (closed)'; + + case NativeType::Scalar: + return is_scalar($other); + + case NativeType::Callable: + return is_callable($other); + + case NativeType::Iterable: + return is_iterable($other); + + default: + return false; + } + } +} diff --git a/src/Framework/DataProviderTestSuite.php b/src/Framework/DataProviderTestSuite.php new file mode 100644 index 00000000000..262530b7a58 --- /dev/null +++ b/src/Framework/DataProviderTestSuite.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function class_exists; +use function count; +use function explode; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\Api\Groups; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DataProviderTestSuite extends TestSuite +{ + /** + * @var list + */ + private array $dependencies = []; + + /** + * @var ?non-empty-list + */ + private ?array $providedTests = null; + + /** + * @param list $dependencies + */ + public function setDependencies(array $dependencies): void + { + $this->dependencies = $dependencies; + + foreach ($this->tests() as $test) { + if (!$test instanceof TestCase) { + continue; + } + + $test->setDependencies($dependencies); + } + } + + /** + * @return non-empty-list + */ + public function provides(): array + { + if ($this->providedTests === null) { + $this->providedTests = [new ExecutionOrderDependency($this->name())]; + } + + return $this->providedTests; + } + + /** + * @return list + */ + public function requires(): array + { + // A DataProviderTestSuite does not have to traverse its child tests + // as these are inherited and cannot reference dataProvider rows directly + return $this->dependencies; + } + + /** + * Returns the size of each test created using the data provider(s). + */ + public function size(): TestSize + { + assert(count(explode('::', $this->name())) === 2); + [$className, $methodName] = explode('::', $this->name()); + + assert(class_exists($className)); + assert($methodName !== ''); + + return (new Groups)->size($className, $methodName); + } +} diff --git a/src/Framework/Exception/AssertionFailedError.php b/src/Framework/Exception/AssertionFailedError.php new file mode 100644 index 00000000000..6bd59c4aea1 --- /dev/null +++ b/src/Framework/Exception/AssertionFailedError.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class AssertionFailedError extends Exception implements SelfDescribing +{ + /** + * Wrapper for getMessage() which is declared as final. + */ + public function toString(): string + { + return $this->getMessage(); + } +} diff --git a/src/Framework/Exception/EmptyStringException.php b/src/Framework/Exception/EmptyStringException.php new file mode 100644 index 00000000000..f5980cd71ab --- /dev/null +++ b/src/Framework/Exception/EmptyStringException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class EmptyStringException extends InvalidArgumentException +{ +} diff --git a/src/Framework/Exception/ErrorLogNotWritableException.php b/src/Framework/Exception/ErrorLogNotWritableException.php new file mode 100644 index 00000000000..602a3e49d63 --- /dev/null +++ b/src/Framework/Exception/ErrorLogNotWritableException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorLogNotWritableException extends Exception +{ + public function __construct() + { + parent::__construct('Could not create writable file for error_log()'); + } +} diff --git a/src/Framework/Exception/Exception.php b/src/Framework/Exception/Exception.php new file mode 100644 index 00000000000..fb45f47d1de --- /dev/null +++ b/src/Framework/Exception/Exception.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_keys; +use function get_object_vars; +use function is_int; +use function sprintf; +use RuntimeException; +use Throwable; + +/** + * Base class for all PHPUnit Framework exceptions. + * + * Ensures that exceptions thrown during a test run do not leave stray + * references behind. + * + * Every Exception contains a stack trace. Each stack frame contains the 'args' + * of the called function. The function arguments can contain references to + * instantiated objects. The references prevent the objects from being + * destructed (until test results are eventually printed), so memory cannot be + * freed up. + * + * With enabled process isolation, test results are serialized in the child + * process and unserialized in the parent process. The stack trace of Exceptions + * may contain objects that cannot be serialized or unserialized (e.g., PDO + * connections). Unserializing user-space objects from the child process into + * the parent would break the intended encapsulation of process isolation. + * + * @see http://fabien.potencier.org/article/9/php-serialization-stack-traces-and-exceptions + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class Exception extends RuntimeException implements \PHPUnit\Exception +{ + /** + * @var list + */ + protected array $serializableTrace; + + public function __construct(string $message = '', int|string $code = 0, ?Throwable $previous = null) + { + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/5965 + */ + if (!is_int($code)) { + $message .= sprintf( + ' (exception code: %s)', + $code, + ); + + $code = 0; + } + + parent::__construct($message, $code, $previous); + + $this->serializableTrace = $this->getTrace(); + + foreach (array_keys($this->serializableTrace) as $key) { + unset($this->serializableTrace[$key]['args']); + } + } + + public function __serialize(): array + { + return get_object_vars($this); + } + + /** + * Returns the serializable trace (without 'args'). + * + * @return list + */ + public function getSerializableTrace(): array + { + return $this->serializableTrace; + } +} diff --git a/src/Framework/Exception/ExpectationFailedException.php b/src/Framework/Exception/ExpectationFailedException.php new file mode 100644 index 00000000000..c46a27bebeb --- /dev/null +++ b/src/Framework/Exception/ExpectationFailedException.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Exception; +use SebastianBergmann\Comparator\ComparisonFailure; + +/** + * Exception for expectations which failed their check. + * + * The exception contains the error message and optionally a + * SebastianBergmann\Comparator\ComparisonFailure which is used to + * generate diff output of the failed expectations. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ExpectationFailedException extends AssertionFailedError +{ + protected ?ComparisonFailure $comparisonFailure = null; + + public function __construct(string $message, ?ComparisonFailure $comparisonFailure = null, ?Exception $previous = null) + { + $this->comparisonFailure = $comparisonFailure; + + parent::__construct($message, 0, $previous); + } + + public function getComparisonFailure(): ?ComparisonFailure + { + return $this->comparisonFailure; + } +} diff --git a/src/Framework/Exception/GeneratorNotSupportedException.php b/src/Framework/Exception/GeneratorNotSupportedException.php new file mode 100644 index 00000000000..b3b179531a6 --- /dev/null +++ b/src/Framework/Exception/GeneratorNotSupportedException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class GeneratorNotSupportedException extends InvalidArgumentException +{ + public static function fromParameterName(string $parameterName): self + { + return new self( + sprintf( + 'Passing an argument of type Generator for the %s parameter is not supported', + $parameterName, + ), + ); + } +} diff --git a/src/Framework/Exception/Incomplete/IncompleteTest.php b/src/Framework/Exception/Incomplete/IncompleteTest.php new file mode 100644 index 00000000000..4492ef226f6 --- /dev/null +++ b/src/Framework/Exception/Incomplete/IncompleteTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface IncompleteTest extends Throwable +{ +} diff --git a/src/Framework/Exception/Incomplete/IncompleteTestError.php b/src/Framework/Exception/Incomplete/IncompleteTestError.php new file mode 100644 index 00000000000..a45564da8fb --- /dev/null +++ b/src/Framework/Exception/Incomplete/IncompleteTestError.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncompleteTestError extends AssertionFailedError implements IncompleteTest +{ +} diff --git a/src/Framework/Exception/InvalidArgumentException.php b/src/Framework/Exception/InvalidArgumentException.php new file mode 100644 index 00000000000..700abf03889 --- /dev/null +++ b/src/Framework/Exception/InvalidArgumentException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class InvalidArgumentException extends Exception +{ +} diff --git a/src/Framework/Exception/InvalidDataProviderException.php b/src/Framework/Exception/InvalidDataProviderException.php new file mode 100644 index 00000000000..b7aa4ae88db --- /dev/null +++ b/src/Framework/Exception/InvalidDataProviderException.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDataProviderException extends Exception +{ + private ?string $providerLabel = null; + + public static function forException(Throwable $e, string $providerLabel): self + { + $exception = new self( + $e->getMessage(), + $e->getCode(), + $e, + ); + $exception->providerLabel = $providerLabel; + + return $exception; + } + + public function getProviderLabel(): ?string + { + return $this->providerLabel; + } +} diff --git a/src/Framework/Exception/InvalidDependencyException.php b/src/Framework/Exception/InvalidDependencyException.php new file mode 100644 index 00000000000..8a636fd4851 --- /dev/null +++ b/src/Framework/Exception/InvalidDependencyException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDependencyException extends AssertionFailedError implements SkippedTest +{ +} diff --git a/src/Framework/Exception/NoChildTestSuiteException.php b/src/Framework/Exception/NoChildTestSuiteException.php new file mode 100644 index 00000000000..e59df81df12 --- /dev/null +++ b/src/Framework/Exception/NoChildTestSuiteException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoChildTestSuiteException extends Exception +{ +} diff --git a/src/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php b/src/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php new file mode 100644 index 00000000000..258b940ae21 --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ActualValueIsNotAnObjectException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ActualValueIsNotAnObjectException extends Exception +{ + public function __construct() + { + parent::__construct( + 'Actual value is not an object', + ); + } +} diff --git a/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.php b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.php new file mode 100644 index 00000000000..74d00a17d76 --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotAcceptParameterTypeException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotAcceptParameterTypeException extends Exception +{ + public function __construct(string $className, string $methodName, string $type) + { + parent::__construct( + sprintf( + '%s is not an accepted argument type for comparison method %s::%s().', + $type, + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php new file mode 100644 index 00000000000..62dc7e8cbbb --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareBoolReturnTypeException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareBoolReturnTypeException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not declare bool return type.', + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php new file mode 100644 index 00000000000..d57607447ae --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareExactlyOneParameterException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareExactlyOneParameterException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not declare exactly one parameter.', + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.php b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.php new file mode 100644 index 00000000000..65718682913 --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotDeclareParameterTypeException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotDeclareParameterTypeException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Parameter of comparison method %s::%s() does not have a declared type.', + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php new file mode 100644 index 00000000000..94590b51062 --- /dev/null +++ b/src/Framework/Exception/ObjectEquals/ComparisonMethodDoesNotExistException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ComparisonMethodDoesNotExistException extends Exception +{ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Comparison method %s::%s() does not exist.', + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/Exception/PhptAssertionFailedError.php b/src/Framework/Exception/PhptAssertionFailedError.php new file mode 100644 index 00000000000..3742abbbc6c --- /dev/null +++ b/src/Framework/Exception/PhptAssertionFailedError.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhptAssertionFailedError extends AssertionFailedError +{ + private readonly string $syntheticFile; + private readonly int $syntheticLine; + + /** + * @var list + */ + private readonly array $syntheticTrace; + private readonly string $diff; + + /** + * @param list $trace + */ + public function __construct(string $message, int $code, string $file, int $line, array $trace, string $diff) + { + parent::__construct($message, $code); + + $this->syntheticFile = $file; + $this->syntheticLine = $line; + $this->syntheticTrace = $trace; + $this->diff = $diff; + } + + public function syntheticFile(): string + { + return $this->syntheticFile; + } + + public function syntheticLine(): int + { + return $this->syntheticLine; + } + + /** + * @return list + */ + public function syntheticTrace(): array + { + return $this->syntheticTrace; + } + + public function diff(): string + { + return $this->diff; + } +} diff --git a/src/Framework/Exception/ProcessIsolationException.php b/src/Framework/Exception/ProcessIsolationException.php new file mode 100644 index 00000000000..e59c9c60358 --- /dev/null +++ b/src/Framework/Exception/ProcessIsolationException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ProcessIsolationException extends Exception +{ +} diff --git a/src/Framework/Exception/Skipped/SkippedTest.php b/src/Framework/Exception/Skipped/SkippedTest.php new file mode 100644 index 00000000000..ab2f6749635 --- /dev/null +++ b/src/Framework/Exception/Skipped/SkippedTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface SkippedTest extends Throwable +{ +} diff --git a/src/Framework/Exception/Skipped/SkippedTestSuiteError.php b/src/Framework/Exception/Skipped/SkippedTestSuiteError.php new file mode 100644 index 00000000000..d3a4788b0cf --- /dev/null +++ b/src/Framework/Exception/Skipped/SkippedTestSuiteError.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SkippedTestSuiteError extends AssertionFailedError implements SkippedTest +{ +} diff --git a/src/Framework/Exception/Skipped/SkippedWithMessageException.php b/src/Framework/Exception/Skipped/SkippedWithMessageException.php new file mode 100644 index 00000000000..d09a760a37c --- /dev/null +++ b/src/Framework/Exception/Skipped/SkippedWithMessageException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SkippedWithMessageException extends AssertionFailedError implements SkippedTest +{ +} diff --git a/src/Framework/Exception/UnknownClassOrInterfaceException.php b/src/Framework/Exception/UnknownClassOrInterfaceException.php new file mode 100644 index 00000000000..6a10f97fb1a --- /dev/null +++ b/src/Framework/Exception/UnknownClassOrInterfaceException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownClassOrInterfaceException extends InvalidArgumentException +{ + public function __construct(string $name) + { + parent::__construct( + sprintf( + 'Class or interface "%s" does not exist', + $name, + ), + ); + } +} diff --git a/src/Framework/Exception/UnknownNativeTypeException.php b/src/Framework/Exception/UnknownNativeTypeException.php new file mode 100644 index 00000000000..09da4609328 --- /dev/null +++ b/src/Framework/Exception/UnknownNativeTypeException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownNativeTypeException extends InvalidArgumentException +{ + public function __construct(string $type) + { + parent::__construct( + sprintf( + 'Native type "%s" is not known', + $type, + ), + ); + } +} diff --git a/src/Framework/ExecutionOrderDependency.php b/src/Framework/ExecutionOrderDependency.php new file mode 100644 index 00000000000..896d2560a4a --- /dev/null +++ b/src/Framework/ExecutionOrderDependency.php @@ -0,0 +1,199 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_filter; +use function array_map; +use function array_values; +use function assert; +use function count; +use function explode; +use function in_array; +use function str_contains; +use PHPUnit\Metadata\DependsOnClass; +use PHPUnit\Metadata\DependsOnMethod; +use Stringable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExecutionOrderDependency implements Stringable +{ + private string $className = ''; + private string $methodName = ''; + private readonly bool $shallowClone; + private readonly bool $deepClone; + + public static function invalid(): self + { + return new self( + '', + '', + false, + false, + ); + } + + public static function forClass(DependsOnClass $metadata): self + { + return new self( + $metadata->className(), + 'class', + $metadata->deepClone(), + $metadata->shallowClone(), + ); + } + + public static function forMethod(DependsOnMethod $metadata): self + { + return new self( + $metadata->className(), + $metadata->methodName(), + $metadata->deepClone(), + $metadata->shallowClone(), + ); + } + + /** + * @param list $dependencies + * + * @return list + */ + public static function filterInvalid(array $dependencies): array + { + return array_values( + array_filter( + $dependencies, + static fn (self $d) => $d->isValid(), + ), + ); + } + + /** + * @param list $existing + * @param list $additional + * + * @return list + */ + public static function mergeUnique(array $existing, array $additional): array + { + $existingTargets = array_map( + static fn (ExecutionOrderDependency $dependency) => $dependency->getTarget(), + $existing, + ); + + foreach ($additional as $dependency) { + $additionalTarget = $dependency->getTarget(); + + if (in_array($additionalTarget, $existingTargets, true)) { + continue; + } + + $existingTargets[] = $additionalTarget; + $existing[] = $dependency; + } + + return $existing; + } + + /** + * @param list $left + * @param list $right + * + * @return list + */ + public static function diff(array $left, array $right): array + { + if ($right === []) { + return $left; + } + + if ($left === []) { + return []; + } + + $diff = []; + $rightTargets = array_map( + static fn (ExecutionOrderDependency $dependency) => $dependency->getTarget(), + $right, + ); + + foreach ($left as $dependency) { + if (in_array($dependency->getTarget(), $rightTargets, true)) { + continue; + } + + $diff[] = $dependency; + } + + return $diff; + } + + public function __construct(string $classOrCallableName, ?string $methodName = null, bool $deepClone = false, bool $shallowClone = false) + { + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + + if ($classOrCallableName === '') { + return; + } + + if (str_contains($classOrCallableName, '::')) { + assert(count(explode('::', $classOrCallableName)) === 2); + [$this->className, $this->methodName] = explode('::', $classOrCallableName); + } else { + $this->className = $classOrCallableName; + $this->methodName = $methodName !== null && $methodName !== '' ? $methodName : 'class'; + } + } + + public function __toString(): string + { + return $this->getTarget(); + } + + /** + * @phpstan-assert-if-true non-empty-string $this->getTarget() + */ + public function isValid(): bool + { + // Invalid dependencies can be declared and are skipped by the runner + return $this->className !== '' && $this->methodName !== ''; + } + + public function shallowClone(): bool + { + return $this->shallowClone; + } + + public function deepClone(): bool + { + return $this->deepClone; + } + + public function targetIsClass(): bool + { + return $this->methodName === 'class'; + } + + public function getTarget(): string + { + return $this->isValid() + ? $this->className . '::' . $this->methodName + : ''; + } + + public function getTargetClassName(): string + { + return $this->className; + } +} diff --git a/src/Framework/MockObject/ConfigurableMethod.php b/src/Framework/MockObject/ConfigurableMethod.php new file mode 100644 index 00000000000..7cce22c3814 --- /dev/null +++ b/src/Framework/MockObject/ConfigurableMethod.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use SebastianBergmann\Type\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConfigurableMethod +{ + /** + * @var non-empty-string + */ + private string $name; + + /** + * @var array + */ + private array $defaultParameterValues; + + /** + * @var non-negative-int + */ + private int $numberOfParameters; + private Type $returnType; + + /** + * @param non-empty-string $name + * @param array $defaultParameterValues + * @param non-negative-int $numberOfParameters + */ + public function __construct(string $name, array $defaultParameterValues, int $numberOfParameters, Type $returnType) + { + $this->name = $name; + $this->defaultParameterValues = $defaultParameterValues; + $this->numberOfParameters = $numberOfParameters; + $this->returnType = $returnType; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + + /** + * @return array + */ + public function defaultParameterValues(): array + { + return $this->defaultParameterValues; + } + + /** + * @return non-negative-int + */ + public function numberOfParameters(): int + { + return $this->numberOfParameters; + } + + public function mayReturn(mixed $value): bool + { + return $this->returnType->isAssignable(Type::fromValue($value, false)); + } + + public function returnTypeDeclaration(): string + { + return $this->returnType->asString(); + } +} diff --git a/src/Framework/MockObject/Exception/BadMethodCallException.php b/src/Framework/MockObject/Exception/BadMethodCallException.php new file mode 100644 index 00000000000..e8ddadda5e1 --- /dev/null +++ b/src/Framework/MockObject/Exception/BadMethodCallException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BadMethodCallException extends \BadMethodCallException implements Exception +{ +} diff --git a/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php b/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php new file mode 100644 index 00000000000..6cb399e53a6 --- /dev/null +++ b/src/Framework/MockObject/Exception/CannotUseOnlyMethodsException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotUseOnlyMethodsException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $type, string $methodName) + { + parent::__construct( + sprintf( + 'Trying to configure method "%s" with onlyMethods(), but it does not exist in class "%s"', + $methodName, + $type, + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/Exception.php b/src/Framework/MockObject/Exception/Exception.php new file mode 100644 index 00000000000..f7994f20f77 --- /dev/null +++ b/src/Framework/MockObject/Exception/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} diff --git a/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php b/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php new file mode 100644 index 00000000000..faf8a498d95 --- /dev/null +++ b/src/Framework/MockObject/Exception/IncompatibleReturnValueException.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function get_debug_type; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncompatibleReturnValueException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(ConfigurableMethod $method, mixed $value) + { + parent::__construct( + sprintf( + 'Method %s may not return value of type %s, its declared return type is "%s"', + $method->name(), + get_debug_type($value), + $method->returnTypeDeclaration(), + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php b/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php new file mode 100644 index 00000000000..8bf8967b066 --- /dev/null +++ b/src/Framework/MockObject/Exception/MatchBuilderNotFoundException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MatchBuilderNotFoundException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $id) + { + parent::__construct( + sprintf( + 'No builder found for match builder identification <%s>', + $id, + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php b/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php new file mode 100644 index 00000000000..de62b867922 --- /dev/null +++ b/src/Framework/MockObject/Exception/MatcherAlreadyRegisteredException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MatcherAlreadyRegisteredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $id) + { + parent::__construct( + sprintf( + 'Matcher with id <%s> is already registered', + $id, + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php b/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php new file mode 100644 index 00000000000..4d39b5d9250 --- /dev/null +++ b/src/Framework/MockObject/Exception/MethodCannotBeConfiguredException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodCannotBeConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $method) + { + parent::__construct( + sprintf( + 'Trying to configure method "%s" which cannot be configured because it does not exist, has not been specified, is final, or is static', + $method, + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php b/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php new file mode 100644 index 00000000000..e4a375927bc --- /dev/null +++ b/src/Framework/MockObject/Exception/MethodNameAlreadyConfiguredException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct() + { + parent::__construct('Method name is already configured'); + } +} diff --git a/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php b/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php new file mode 100644 index 00000000000..25c11341660 --- /dev/null +++ b/src/Framework/MockObject/Exception/MethodNameNotConfiguredException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameNotConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct() + { + parent::__construct('Method name is not configured'); + } +} diff --git a/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php b/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php new file mode 100644 index 00000000000..fba96cf45c9 --- /dev/null +++ b/src/Framework/MockObject/Exception/MethodParametersAlreadyConfiguredException.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodParametersAlreadyConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct() + { + parent::__construct('Method parameters already configured'); + } +} diff --git a/src/Framework/MockObject/Exception/NeverReturningMethodException.php b/src/Framework/MockObject/Exception/NeverReturningMethodException.php new file mode 100644 index 00000000000..3e565cea836 --- /dev/null +++ b/src/Framework/MockObject/Exception/NeverReturningMethodException.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NeverReturningMethodException extends RuntimeException implements Exception +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function __construct(string $className, string $methodName) + { + parent::__construct( + sprintf( + 'Method %s::%s() is declared to never return', + $className, + $methodName, + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php b/src/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php new file mode 100644 index 00000000000..c4b181653f9 --- /dev/null +++ b/src/Framework/MockObject/Exception/NoMoreReturnValuesConfiguredException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoMoreReturnValuesConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(Invocation $invocation, int $numberOfConfiguredReturnValues) + { + parent::__construct( + sprintf( + 'Only %d return values have been configured for %s::%s()', + $numberOfConfiguredReturnValues, + $invocation->className(), + $invocation->methodName(), + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php b/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php new file mode 100644 index 00000000000..cf193f10c14 --- /dev/null +++ b/src/Framework/MockObject/Exception/ReturnValueNotConfiguredException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnValueNotConfiguredException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(Invocation $invocation) + { + parent::__construct( + sprintf( + 'No return value is configured for %s::%s() and return value generation is disabled', + $invocation->className(), + $invocation->methodName(), + ), + ); + } +} diff --git a/src/Framework/MockObject/Exception/RuntimeException.php b/src/Framework/MockObject/Exception/RuntimeException.php new file mode 100644 index 00000000000..b99a903e5d1 --- /dev/null +++ b/src/Framework/MockObject/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements Exception +{ +} diff --git a/src/Framework/MockObject/Generator/DoubledClass.php b/src/Framework/MockObject/Generator/DoubledClass.php new file mode 100644 index 00000000000..3d88c72e331 --- /dev/null +++ b/src/Framework/MockObject/Generator/DoubledClass.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function class_exists; +use PHPUnit\Framework\MockObject\ConfigurableMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DoubledClass +{ + private string $classCode; + + /** + * @var class-string + */ + private string $mockName; + + /** + * @var list + */ + private array $configurableMethods; + + /** + * @param class-string $mockName + * @param list $configurableMethods + */ + public function __construct(string $classCode, string $mockName, array $configurableMethods) + { + $this->classCode = $classCode; + $this->mockName = $mockName; + $this->configurableMethods = $configurableMethods; + } + + /** + * @return class-string + */ + public function generate(): string + { + if (!class_exists($this->mockName, false)) { + eval($this->classCode); + } + + return $this->mockName; + } + + public function classCode(): string + { + return $this->classCode; + } + + /** + * @return list + */ + public function configurableMethods(): array + { + return $this->configurableMethods; + } +} diff --git a/src/Framework/MockObject/Generator/DoubledMethod.php b/src/Framework/MockObject/Generator/DoubledMethod.php new file mode 100644 index 00000000000..09006b257c2 --- /dev/null +++ b/src/Framework/MockObject/Generator/DoubledMethod.php @@ -0,0 +1,395 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_key_exists; +use function assert; +use function count; +use function explode; +use function implode; +use function is_object; +use function is_string; +use function preg_match; +use function preg_replace; +use function str_contains; +use function strlen; +use function strpos; +use function substr; +use function substr_count; +use function trim; +use function var_export; +use ReflectionMethod; +use ReflectionParameter; +use SebastianBergmann\Type\ReflectionMapper; +use SebastianBergmann\Type\Type; +use SebastianBergmann\Type\UnknownType; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DoubledMethod +{ + use TemplateLoader; + + /** + * @var class-string + */ + private readonly string $className; + + /** + * @var non-empty-string + */ + private readonly string $methodName; + private readonly string $modifier; + private readonly string $argumentsForDeclaration; + private readonly string $argumentsForCall; + private readonly Type $returnType; + private readonly string $reference; + private readonly bool $static; + private readonly ?string $deprecation; + + /** + * @var array + */ + private readonly array $defaultParameterValues; + + /** + * @var non-negative-int + */ + private readonly int $numberOfParameters; + + /** + * @throws ReflectionException + * @throws RuntimeException + */ + public static function fromReflection(ReflectionMethod $method): self + { + if ($method->isPrivate()) { + $modifier = 'private'; + } elseif ($method->isProtected()) { + $modifier = 'protected'; + } else { + $modifier = 'public'; + } + + if ($method->isStatic()) { + $modifier .= ' static'; + } + + if ($method->returnsReference()) { + $reference = '&'; + } else { + $reference = ''; + } + + $docComment = $method->getDocComment(); + + if (is_string($docComment) && + preg_match('#\*[ \t]*+@deprecated[ \t]*+(.*?)\r?+\n[ \t]*+\*(?:[ \t]*+@|/$)#s', $docComment, $deprecation) > 0 + ) { + $deprecation = trim(preg_replace('#[ \t]*\r?\n[ \t]*+\*[ \t]*+#', ' ', $deprecation[1])); + } else { + $deprecation = null; + } + + return new self( + $method->getDeclaringClass()->getName(), + $method->getName(), + $modifier, + self::methodParametersForDeclaration($method), + self::methodParametersForCall($method), + self::methodParametersDefaultValues($method), + count($method->getParameters()), + (new ReflectionMapper)->fromReturnType($method), + $reference, + $method->isStatic(), + $deprecation, + ); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function fromName(string $className, string $methodName): self + { + return new self( + $className, + $methodName, + 'public', + '', + '', + [], + 0, + new UnknownType, + '', + false, + null, + ); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param array $defaultParameterValues + * @param non-negative-int $numberOfParameters + */ + private function __construct(string $className, string $methodName, string $modifier, string $argumentsForDeclaration, string $argumentsForCall, array $defaultParameterValues, int $numberOfParameters, Type $returnType, string $reference, bool $static, ?string $deprecation) + { + $this->className = $className; + $this->methodName = $methodName; + $this->modifier = $modifier; + $this->argumentsForDeclaration = $argumentsForDeclaration; + $this->argumentsForCall = $argumentsForCall; + $this->defaultParameterValues = $defaultParameterValues; + $this->numberOfParameters = $numberOfParameters; + $this->returnType = $returnType; + $this->reference = $reference; + $this->static = $static; + $this->deprecation = $deprecation; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + /** + * @throws RuntimeException + */ + public function generateCode(): string + { + if ($this->static) { + $templateFile = 'doubled_static_method.tpl'; + } else { + $templateFile = 'doubled_method.tpl'; + } + + $deprecation = $this->deprecation; + $returnResult = ''; + + if (!$this->returnType->isNever() && !$this->returnType->isVoid()) { + $returnResult = <<<'EOT' + + + return $__phpunit_result; +EOT; + } + + if (null !== $this->deprecation) { + $deprecation = "The {$this->className}::{$this->methodName} method is deprecated ({$this->deprecation})."; + $deprecationTemplate = $this->loadTemplate('deprecation.tpl'); + + $deprecationTemplate->setVar( + [ + 'deprecation' => var_export($deprecation, true), + ], + ); + + $deprecation = $deprecationTemplate->render(); + } + + $template = $this->loadTemplate($templateFile); + + $argumentsCount = 0; + + if (str_contains($this->argumentsForCall, '...')) { + $argumentsCount = null; + } elseif ($this->argumentsForCall !== '') { + $argumentsCount = substr_count($this->argumentsForCall, ',') + 1; + } + + $returnDeclaration = ''; + $returnTypeAsString = $this->returnType->asString(); + + if ($returnTypeAsString !== '') { + $returnDeclaration = ': ' . $returnTypeAsString; + } + + $template->setVar( + [ + 'arguments_decl' => $this->argumentsForDeclaration, + 'arguments_call' => $this->argumentsForCall, + 'return_declaration' => $returnDeclaration, + 'return_type' => $this->returnType->asString(), + 'arguments_count' => (string) $argumentsCount, + 'class_name' => $this->className, + 'method_name' => $this->methodName, + 'modifier' => $this->modifier, + 'reference' => $this->reference, + 'deprecation' => $deprecation, + 'return_result' => $returnResult, + ], + ); + + return $template->render(); + } + + public function returnType(): Type + { + return $this->returnType; + } + + /** + * @return array + */ + public function defaultParameterValues(): array + { + return $this->defaultParameterValues; + } + + /** + * @return non-negative-int + */ + public function numberOfParameters(): int + { + return $this->numberOfParameters; + } + + /** + * Returns the parameters of a function or method. + * + * @throws RuntimeException + */ + private static function methodParametersForDeclaration(ReflectionMethod $method): string + { + $parameters = []; + $types = (new ReflectionMapper)->fromParameterTypes($method); + + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + + /* Note: PHP extensions may use empty names for reference arguments + * or "..." for methods taking a variable number of arguments. + */ + if ($name === '$' || $name === '$...') { + $name = '$arg' . $i; + } + + $default = ''; + $reference = ''; + $typeDeclaration = ''; + + assert(array_key_exists($i, $types)); + + if (!$types[$i]->type()->isUnknown()) { + $typeDeclaration = $types[$i]->type()->asString() . ' '; + } + + if ($parameter->isPassedByReference()) { + $reference = '&'; + } + + if ($parameter->isVariadic()) { + $name = '...' . $name; + } elseif ($parameter->isDefaultValueAvailable()) { + $default = ' = ' . self::exportDefaultValue($parameter); + } elseif ($parameter->isOptional()) { + $default = ' = null'; + } + + $parameters[] = $typeDeclaration . $reference . $name . $default; + } + + return implode(', ', $parameters); + } + + /** + * Returns the parameters of a function or method. + * + * @throws ReflectionException + */ + private static function methodParametersForCall(ReflectionMethod $method): string + { + $parameters = []; + + foreach ($method->getParameters() as $i => $parameter) { + $name = '$' . $parameter->getName(); + + /* Note: PHP extensions may use empty names for reference arguments + * or "..." for methods taking a variable number of arguments. + */ + if ($name === '$' || $name === '$...') { + $name = '$arg' . $i; + } + + if ($parameter->isVariadic()) { + continue; + } + + if ($parameter->isPassedByReference()) { + $parameters[] = '&' . $name; + } else { + $parameters[] = $name; + } + } + + return implode(', ', $parameters); + } + + /** + * @throws ReflectionException + */ + private static function exportDefaultValue(ReflectionParameter $parameter): string + { + try { + $defaultValue = $parameter->getDefaultValue(); + + if (!is_object($defaultValue)) { + return var_export($defaultValue, true); + } + + $parameterAsString = $parameter->__toString(); + + return explode( + ' = ', + substr( + substr( + $parameterAsString, + strpos($parameterAsString, ' ') + strlen(' '), + ), + 0, + -2, + ), + )[1]; + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new ReflectionException( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + // @codeCoverageIgnoreEnd + } + + /** + * @return array + */ + private static function methodParametersDefaultValues(ReflectionMethod $method): array + { + $result = []; + + foreach ($method->getParameters() as $i => $parameter) { + if (!$parameter->isDefaultValueAvailable()) { + continue; + } + + $result[$i] = $parameter->getDefaultValue(); + } + + return $result; + } +} diff --git a/src/Framework/MockObject/Generator/DoubledMethodSet.php b/src/Framework/MockObject/Generator/DoubledMethodSet.php new file mode 100644 index 00000000000..6a2d29f4f7d --- /dev/null +++ b/src/Framework/MockObject/Generator/DoubledMethodSet.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_key_exists; +use function array_values; +use function strtolower; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DoubledMethodSet +{ + /** + * @var array + */ + private array $methods = []; + + public function addMethods(DoubledMethod ...$methods): void + { + foreach ($methods as $method) { + $this->methods[strtolower($method->methodName())] = $method; + } + } + + /** + * @return list + */ + public function asArray(): array + { + return array_values($this->methods); + } + + public function hasMethod(string $methodName): bool + { + return array_key_exists(strtolower($methodName), $this->methods); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.php b/src/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.php new file mode 100644 index 00000000000..e2cde18b68b --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/ClassIsEnumerationException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsEnumerationException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $className) + { + parent::__construct( + sprintf( + 'Class "%s" is an enumeration and cannot be doubled', + $className, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/ClassIsFinalException.php b/src/Framework/MockObject/Generator/Exception/ClassIsFinalException.php new file mode 100644 index 00000000000..f10100b90de --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/ClassIsFinalException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsFinalException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $className) + { + parent::__construct( + sprintf( + 'Class "%s" is declared "final" and cannot be doubled', + $className, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/DuplicateMethodException.php b/src/Framework/MockObject/Generator/Exception/DuplicateMethodException.php new file mode 100644 index 00000000000..b18ed4f561e --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/DuplicateMethodException.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function array_diff_assoc; +use function array_unique; +use function implode; +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DuplicateMethodException extends \PHPUnit\Framework\Exception implements Exception +{ + /** + * @param list $methods + */ + public function __construct(array $methods) + { + parent::__construct( + sprintf( + 'Cannot double using a method list that contains duplicates: "%s" (duplicate: "%s")', + implode(', ', $methods), + implode(', ', array_unique(array_diff_assoc($methods, array_unique($methods)))), + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/Exception.php b/src/Framework/MockObject/Generator/Exception/Exception.php new file mode 100644 index 00000000000..8d62606fca2 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use PHPUnit\Framework\MockObject\Exception as BaseException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends BaseException +{ +} diff --git a/src/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php b/src/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php new file mode 100644 index 00000000000..32296ce3940 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/InvalidMethodNameException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidMethodNameException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $method) + { + parent::__construct( + sprintf( + 'Cannot double method with invalid name "%s"', + $method, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/MethodNamedMethodException.php b/src/Framework/MockObject/Generator/Exception/MethodNamedMethodException.php new file mode 100644 index 00000000000..78586fe1067 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/MethodNamedMethodException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNamedMethodException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct() + { + parent::__construct('Doubling interfaces (or classes) that have a method named "method" is not supported.'); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.php b/src/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.php new file mode 100644 index 00000000000..eec81c065d5 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/NameAlreadyInUseException.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NameAlreadyInUseException extends \PHPUnit\Framework\Exception implements Exception +{ + /** + * @param class-string|trait-string $name + */ + public function __construct(string $name) + { + parent::__construct( + sprintf( + 'The name "%s" is already in use', + $name, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/ReflectionException.php b/src/Framework/MockObject/Generator/Exception/ReflectionException.php new file mode 100644 index 00000000000..f4a84f18e6e --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/ReflectionException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReflectionException extends \PHPUnit\Framework\Exception implements Exception +{ +} diff --git a/src/Framework/MockObject/Generator/Exception/RuntimeException.php b/src/Framework/MockObject/Generator/Exception/RuntimeException.php new file mode 100644 index 00000000000..eed41c37a33 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \PHPUnit\Framework\Exception implements Exception +{ +} diff --git a/src/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php b/src/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php new file mode 100644 index 00000000000..95f03e73291 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/UnknownInterfaceException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownInterfaceException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $interfaceName) + { + parent::__construct( + sprintf( + 'Interface "%s" does not exist', + $interfaceName, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Exception/UnknownTypeException.php b/src/Framework/MockObject/Generator/Exception/UnknownTypeException.php new file mode 100644 index 00000000000..cd1e1e072b1 --- /dev/null +++ b/src/Framework/MockObject/Generator/Exception/UnknownTypeException.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnknownTypeException extends \PHPUnit\Framework\Exception implements Exception +{ + public function __construct(string $type) + { + parent::__construct( + sprintf( + 'Class or interface "%s" does not exist', + $type, + ), + ); + } +} diff --git a/src/Framework/MockObject/Generator/Generator.php b/src/Framework/MockObject/Generator/Generator.php new file mode 100644 index 00000000000..1794d327ea3 --- /dev/null +++ b/src/Framework/MockObject/Generator/Generator.php @@ -0,0 +1,887 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use const PHP_EOL; +use const PHP_VERSION; +use function array_merge; +use function array_pop; +use function array_unique; +use function assert; +use function class_exists; +use function count; +use function explode; +use function implode; +use function in_array; +use function interface_exists; +use function is_array; +use function md5; +use function mt_rand; +use function preg_match; +use function serialize; +use function sort; +use function sprintf; +use function substr; +use function trait_exists; +use function version_compare; +use Exception; +use Iterator; +use IteratorAggregate; +use PHPUnit\Framework\MockObject\ConfigurableMethod; +use PHPUnit\Framework\MockObject\DoubledCloneMethod; +use PHPUnit\Framework\MockObject\Method; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\MockObjectApi; +use PHPUnit\Framework\MockObject\MockObjectInternal; +use PHPUnit\Framework\MockObject\ProxiedCloneMethod; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\MockObject\StubApi; +use PHPUnit\Framework\MockObject\StubInternal; +use PHPUnit\Framework\MockObject\TestDoubleState; +use PropertyHookType; +use ReflectionClass; +use ReflectionMethod; +use ReflectionObject; +use SebastianBergmann\Type\ReflectionMapper; +use SebastianBergmann\Type\Type; +use Throwable; +use Traversable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Generator +{ + use TemplateLoader; + + /** + * @var null|non-empty-array + */ + private static ?array $excludedMethodNames = null; + + /** + * @var array + */ + private static array $cache = []; + + /** + * Returns a test double for the specified class. + * + * @param class-string $type + * @param ?list $methods + * @param array $arguments + * + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + */ + public function testDouble(string $type, bool $mockObject, ?array $methods = [], array $arguments = [], string $mockClassName = '', bool $callOriginalConstructor = true, bool $callOriginalClone = true, bool $returnValueGeneration = true): MockObject|Stub + { + if ($type === Traversable::class) { + $type = Iterator::class; + } + + $this->ensureKnownType($type); + $this->ensureValidMethods($methods); + $this->ensureNameForTestDoubleClassIsAvailable($mockClassName); + + $mock = $this->generate( + $type, + $mockObject, + $methods, + $mockClassName, + $callOriginalClone, + ); + + $object = $this->instantiate( + $mock, + $callOriginalConstructor, + $arguments, + $returnValueGeneration, + ); + + assert($object instanceof $type); + + if ($mockObject) { + assert($object instanceof MockObject); + } else { + assert($object instanceof Stub); + } + + return $object; + } + + /** + * @param list $interfaces + * + * @throws RuntimeException + * @throws UnknownInterfaceException + */ + public function testDoubleForInterfaceIntersection(array $interfaces, bool $mockObject, bool $returnValueGeneration = true): MockObject|Stub + { + if (count($interfaces) < 2) { + throw new RuntimeException('At least two interfaces must be specified'); + } + + foreach ($interfaces as $interface) { + if (!interface_exists($interface)) { + throw new UnknownInterfaceException($interface); + } + } + + sort($interfaces); + + $methods = []; + + foreach ($interfaces as $interface) { + $methods = array_merge($methods, $this->namesOfMethodsIn($interface)); + } + + if (count(array_unique($methods)) < count($methods)) { + throw new RuntimeException('Interfaces must not declare the same method'); + } + + $unqualifiedNames = []; + + foreach ($interfaces as $interface) { + $parts = explode('\\', $interface); + $unqualifiedNames[] = array_pop($parts); + } + + sort($unqualifiedNames); + + do { + $intersectionName = sprintf( + 'Intersection_%s_%s', + implode('_', $unqualifiedNames), + substr(md5((string) mt_rand()), 0, 8), + ); + } while (interface_exists($intersectionName, false)); + + $template = $this->loadTemplate('intersection.tpl'); + + $template->setVar( + [ + 'intersection' => $intersectionName, + 'interfaces' => implode(', ', $interfaces), + ], + ); + + eval($template->render()); + + assert(interface_exists($intersectionName)); + + return $this->testDouble( + $intersectionName, + $mockObject, + returnValueGeneration: $returnValueGeneration, + ); + } + + /** + * @param class-string $type + * @param ?list $methods + * + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws ReflectionException + * @throws RuntimeException + * + * @todo This method is only public because it is used to test generated code in PHPT tests + * + * @see https://github.com/sebastianbergmann/phpunit/issues/5476 + */ + public function generate(string $type, bool $mockObject, ?array $methods = null, string $mockClassName = '', bool $callOriginalClone = true): DoubledClass + { + if ($mockClassName !== '') { + return $this->generateCodeForTestDoubleClass( + $type, + $mockObject, + $methods, + $mockClassName, + $callOriginalClone, + ); + } + + $key = md5( + $type . + ($mockObject ? 'MockObject' : 'TestStub') . + serialize($methods) . + serialize($callOriginalClone), + ); + + if (!isset(self::$cache[$key])) { + self::$cache[$key] = $this->generateCodeForTestDoubleClass( + $type, + $mockObject, + $methods, + $mockClassName, + $callOriginalClone, + ); + } + + return self::$cache[$key]; + } + + /** + * @param class-string $className + * + * @throws ReflectionException + * + * @return list + */ + private function mockClassMethods(string $className): array + { + $class = $this->reflectClass($className); + $methods = []; + + foreach ($class->getMethods() as $method) { + if (($method->isPublic() || $method->isAbstract()) && $this->canMethodBeDoubled($method)) { + $methods[] = DoubledMethod::fromReflection($method); + } + } + + return $methods; + } + + /** + * @param class-string $interfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function userDefinedInterfaceMethods(string $interfaceName): array + { + $interface = $this->reflectClass($interfaceName); + $methods = []; + + foreach ($interface->getMethods() as $method) { + if (!$method->isUserDefined()) { + continue; + } + + $methods[] = $method; + } + + return $methods; + } + + /** + * @param array $arguments + * + * @throws ReflectionException + * @throws RuntimeException + */ + private function instantiate(DoubledClass $mockClass, bool $callOriginalConstructor = false, array $arguments = [], bool $returnValueGeneration = true): object + { + $className = $mockClass->generate(); + + try { + $object = new ReflectionClass($className)->newInstanceWithoutConstructor(); + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new ReflectionException( + $e->getMessage(), + $e->getCode(), + $e, + ); + // @codeCoverageIgnoreEnd + } + + $reflector = new ReflectionObject($object); + + /** + * @noinspection PhpUnhandledExceptionInspection + */ + $reflector->getProperty('__phpunit_state')->setValue( + $object, + new TestDoubleState($mockClass->configurableMethods(), $returnValueGeneration), + ); + + if ($callOriginalConstructor && $reflector->getConstructor() !== null) { + try { + $reflector->getConstructor()->invokeArgs($object, $arguments); + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new ReflectionException( + $e->getMessage(), + $e->getCode(), + $e, + ); + // @codeCoverageIgnoreEnd + } + } + + return $object; + } + + /** + * @param class-string $type + * @param ?list $explicitMethods + * + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws MethodNamedMethodException + * @throws ReflectionException + * @throws RuntimeException + */ + private function generateCodeForTestDoubleClass(string $type, bool $mockObject, ?array $explicitMethods, string $mockClassName, bool $callOriginalClone): DoubledClass + { + $classTemplate = $this->loadTemplate('test_double_class.tpl'); + $additionalInterfaces = []; + $doubledCloneMethod = false; + $proxiedCloneMethod = false; + $isClass = false; + $isReadonly = false; + $isInterface = false; + $mockMethods = new DoubledMethodSet; + $testDoubleClassPrefix = $mockObject ? 'MockObject_' : 'TestStub_'; + + $_mockClassName = $this->generateClassName( + $type, + $mockClassName, + $testDoubleClassPrefix, + ); + + if (class_exists($_mockClassName['fullClassName'])) { + $isClass = true; + } elseif (interface_exists($_mockClassName['fullClassName'])) { + $isInterface = true; + } + + $class = $this->reflectClass($_mockClassName['fullClassName']); + + if ($class->isEnum()) { + throw new ClassIsEnumerationException($_mockClassName['fullClassName']); + } + + if ($class->isFinal()) { + throw new ClassIsFinalException($_mockClassName['fullClassName']); + } + + if ($class->isReadOnly()) { + $isReadonly = true; + } + + // @see https://github.com/sebastianbergmann/phpunit/issues/2995 + if ($isInterface && $class->implementsInterface(Throwable::class)) { + $actualClassName = Exception::class; + $additionalInterfaces[] = $class->getName(); + $isInterface = false; + $class = $this->reflectClass($actualClassName); + + foreach ($this->userDefinedInterfaceMethods($_mockClassName['fullClassName']) as $method) { + $methodName = $method->getName(); + + if ($class->hasMethod($methodName)) { + $classMethod = $class->getMethod($methodName); + + if (!$this->canMethodBeDoubled($classMethod)) { + continue; + } + } + + $mockMethods->addMethods( + DoubledMethod::fromReflection($method), + ); + } + + $_mockClassName = $this->generateClassName( + $actualClassName, + $_mockClassName['className'], + $testDoubleClassPrefix, + ); + } + + // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/103 + if ($isInterface && $class->implementsInterface(Traversable::class) && + !$class->implementsInterface(Iterator::class) && + !$class->implementsInterface(IteratorAggregate::class)) { + $additionalInterfaces[] = Iterator::class; + + $mockMethods->addMethods( + ...$this->mockClassMethods(Iterator::class), + ); + } + + if ($class->hasMethod('__clone')) { + $cloneMethod = $class->getMethod('__clone'); + + if (!$cloneMethod->isFinal()) { + if ($callOriginalClone && !$isInterface) { + $proxiedCloneMethod = true; + } else { + $doubledCloneMethod = true; + } + } + } else { + $doubledCloneMethod = true; + } + + if ($isClass && $explicitMethods === []) { + $mockMethods->addMethods( + ...$this->mockClassMethods($_mockClassName['fullClassName']), + ); + } + + if ($isInterface && ($explicitMethods === [] || $explicitMethods === null)) { + $mockMethods->addMethods( + ...$this->interfaceMethods($_mockClassName['fullClassName']), + ); + } + + if (is_array($explicitMethods)) { + foreach ($explicitMethods as $methodName) { + if ($class->hasMethod($methodName)) { + $method = $class->getMethod($methodName); + + if ($this->canMethodBeDoubled($method)) { + $mockMethods->addMethods( + DoubledMethod::fromReflection($method), + ); + } + } else { + $mockMethods->addMethods( + DoubledMethod::fromName( + $_mockClassName['fullClassName'], + $methodName, + ), + ); + } + } + } + + $propertiesWithHooks = $this->properties($class); + $configurableMethods = $this->configurableMethods($mockMethods, $propertiesWithHooks); + + $mockedMethods = ''; + + foreach ($mockMethods->asArray() as $mockMethod) { + $mockedMethods .= $mockMethod->generateCode(); + } + + /** @var trait-string[] $traits */ + $traits = [StubApi::class]; + + if ($mockObject) { + $traits[] = MockObjectApi::class; + } + + if ($mockMethods->hasMethod('method') || $class->hasMethod('method')) { + throw new MethodNamedMethodException; + } + + $traits[] = Method::class; + + if ($doubledCloneMethod) { + $traits[] = DoubledCloneMethod::class; + } elseif ($proxiedCloneMethod) { + $traits[] = ProxiedCloneMethod::class; + } + + $useStatements = ''; + + foreach ($traits as $trait) { + $useStatements .= sprintf( + ' use %s;' . PHP_EOL, + $trait, + ); + } + + unset($traits); + + $classTemplate->setVar( + [ + 'class_declaration' => $this->generateTestDoubleClassDeclaration( + $mockObject, + $_mockClassName, + $isInterface, + $additionalInterfaces, + $isReadonly, + ), + 'use_statements' => $useStatements, + 'mock_class_name' => $_mockClassName['className'], + 'methods' => $mockedMethods, + 'property_hooks' => (new HookedPropertyGenerator)->generate( + $_mockClassName['className'], + $propertiesWithHooks, + ), + ], + ); + + return new DoubledClass( + $classTemplate->render(), + $_mockClassName['className'], + $configurableMethods, + ); + } + + /** + * @param class-string $type + * + * @return array{className: class-string, originalClassName: class-string, fullClassName: class-string, namespaceName: string} + */ + private function generateClassName(string $type, string $className, string $prefix): array + { + if ($type[0] === '\\') { + $type = substr($type, 1); + } + + $classNameParts = explode('\\', $type); + + if (count($classNameParts) > 1) { + $type = array_pop($classNameParts); + $namespaceName = implode('\\', $classNameParts); + $fullClassName = $namespaceName . '\\' . $type; + } else { + $namespaceName = ''; + $fullClassName = $type; + } + + if ($className === '') { + do { + $className = $prefix . $type . '_' . + substr(md5((string) mt_rand()), 0, 8); + } while (class_exists($className, false)); + } + + return [ + 'className' => $className, + 'originalClassName' => $type, + 'fullClassName' => $fullClassName, + 'namespaceName' => $namespaceName, + ]; + } + + /** + * @param array{className: non-empty-string, originalClassName: non-empty-string, fullClassName: non-empty-string, namespaceName: string} $mockClassName + * @param list $additionalInterfaces + */ + private function generateTestDoubleClassDeclaration(bool $mockObject, array $mockClassName, bool $isInterface, array $additionalInterfaces, bool $isReadonly): string + { + if ($mockObject) { + $additionalInterfaces[] = MockObjectInternal::class; + } else { + $additionalInterfaces[] = StubInternal::class; + } + + if ($isReadonly) { + $buffer = 'readonly class '; + } else { + $buffer = 'class '; + } + + $interfaces = implode(', ', $additionalInterfaces); + + if ($isInterface) { + $buffer .= sprintf( + '%s implements %s', + $mockClassName['className'], + $interfaces, + ); + + if (!in_array($mockClassName['originalClassName'], $additionalInterfaces, true)) { + $buffer .= ', '; + + if ($mockClassName['namespaceName'] !== '') { + $buffer .= $mockClassName['namespaceName'] . '\\'; + } + + $buffer .= $mockClassName['originalClassName']; + } + } else { + $buffer .= sprintf( + '%s extends %s%s implements %s', + $mockClassName['className'], + $mockClassName['namespaceName'] !== '' ? $mockClassName['namespaceName'] . '\\' : '', + $mockClassName['originalClassName'], + $interfaces, + ); + } + + return $buffer; + } + + private function canMethodBeDoubled(ReflectionMethod $method): bool + { + if ($method->isConstructor()) { + return false; + } + + if ($method->isDestructor()) { + return false; + } + + if ($method->isFinal()) { + return false; + } + + if ($method->isPrivate()) { + return false; + } + + return !$this->isMethodNameExcluded($method->getName()); + } + + private function isMethodNameExcluded(string $name): bool + { + if (self::$excludedMethodNames === null) { + self::$excludedMethodNames = [ + '__CLASS__' => true, + '__DIR__' => true, + '__FILE__' => true, + '__FUNCTION__' => true, + '__LINE__' => true, + '__METHOD__' => true, + '__NAMESPACE__' => true, + '__TRAIT__' => true, + '__clone' => true, + '__halt_compiler' => true, + ]; + + if (version_compare(PHP_VERSION, '8.5', '>=')) { + self::$excludedMethodNames['__sleep'] = true; + self::$excludedMethodNames['__wakeup'] = true; + } + } + + return isset(self::$excludedMethodNames[$name]); + } + + /** + * @throws UnknownTypeException + */ + private function ensureKnownType(string $type): void + { + if (!class_exists($type) && !interface_exists($type)) { + throw new UnknownTypeException($type); + } + } + + /** + * @param ?list $methods + * + * @throws DuplicateMethodException + * @throws InvalidMethodNameException + */ + private function ensureValidMethods(?array $methods): void + { + if ($methods === null) { + return; + } + + foreach ($methods as $method) { + if (!preg_match('~[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*~', (string) $method)) { + throw new InvalidMethodNameException((string) $method); + } + } + + if ($methods !== array_unique($methods)) { + throw new DuplicateMethodException($methods); + } + } + + /** + * @throws NameAlreadyInUseException + * @throws ReflectionException + */ + private function ensureNameForTestDoubleClassIsAvailable(string $className): void + { + if ($className === '') { + return; + } + + if (class_exists($className, false) || + interface_exists($className, false) || + trait_exists($className, false)) { + throw new NameAlreadyInUseException($className); + } + } + + /** + * @template T of object + * + * @param class-string $className + * + * @throws ReflectionException + * + * @return ReflectionClass + * + * @phpstan-ignore throws.unusedType + */ + private function reflectClass(string $className): ReflectionClass + { + try { + $class = new ReflectionClass($className); + + // @codeCoverageIgnoreStart + /** @phpstan-ignore catch.neverThrown */ + } catch (\ReflectionException $e) { + throw new ReflectionException( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + // @codeCoverageIgnoreEnd + + return $class; + } + + /** + * @param class-string $classOrInterfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function namesOfMethodsIn(string $classOrInterfaceName): array + { + $class = $this->reflectClass($classOrInterfaceName); + $methods = []; + + foreach ($class->getMethods() as $method) { + if ($method->isPublic() || $method->isAbstract()) { + $methods[] = $method->getName(); + } + } + + return $methods; + } + + /** + * @param class-string $interfaceName + * + * @throws ReflectionException + * + * @return list + */ + private function interfaceMethods(string $interfaceName): array + { + $class = $this->reflectClass($interfaceName); + $methods = []; + + foreach ($class->getMethods() as $method) { + $methods[] = DoubledMethod::fromReflection($method); + } + + return $methods; + } + + /** + * @param list $propertiesWithHooks + * + * @return list + */ + private function configurableMethods(DoubledMethodSet $methods, array $propertiesWithHooks): array + { + $configurable = []; + + foreach ($methods->asArray() as $method) { + $configurable[] = new ConfigurableMethod( + $method->methodName(), + $method->defaultParameterValues(), + $method->numberOfParameters(), + $method->returnType(), + ); + } + + foreach ($propertiesWithHooks as $property) { + if ($property->hasGetHook()) { + $configurable[] = new ConfigurableMethod( + sprintf( + '$%s::get', + $property->name(), + ), + [], + 0, + $property->type(), + ); + } + + if ($property->hasSetHook()) { + $configurable[] = new ConfigurableMethod( + sprintf( + '$%s::set', + $property->name(), + ), + [], + 1, + Type::fromName('void', false), + ); + } + } + + return $configurable; + } + + /** + * @param ?ReflectionClass $class + * + * @return list + */ + private function properties(?ReflectionClass $class): array + { + if ($class === null) { + return []; + } + + $mapper = new ReflectionMapper; + $properties = []; + + foreach ($class->getProperties() as $property) { + if (!$property->isPublic()) { + continue; + } + + if ($property->isFinal()) { + continue; + } + + if (!$property->hasHooks()) { + continue; + } + + $hasGetHook = false; + $hasSetHook = false; + + if ($property->hasHook(PropertyHookType::Get) && + !$property->getHook(PropertyHookType::Get)->isFinal()) { + $hasGetHook = true; + } + + if ($property->hasHook(PropertyHookType::Set) && + !$property->getHook(PropertyHookType::Set)->isFinal()) { + $hasSetHook = true; + } + + if (!$hasGetHook && !$hasSetHook) { + continue; + } + + $properties[] = new HookedProperty( + $property->getName(), + $mapper->fromPropertyType($property), + $hasGetHook, + $hasSetHook, + ); + } + + return $properties; + } +} diff --git a/src/Framework/MockObject/Generator/HookedProperty.php b/src/Framework/MockObject/Generator/HookedProperty.php new file mode 100644 index 00000000000..e43d589d7e7 --- /dev/null +++ b/src/Framework/MockObject/Generator/HookedProperty.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use SebastianBergmann\Type\Type; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HookedProperty +{ + /** + * @var non-empty-string + */ + private string $name; + private Type $type; + private bool $getHook; + private bool $setHook; + + /** + * @param non-empty-string $name + */ + public function __construct(string $name, Type $type, bool $getHook, bool $setHook) + { + $this->name = $name; + $this->type = $type; + $this->getHook = $getHook; + $this->setHook = $setHook; + } + + public function name(): string + { + return $this->name; + } + + public function type(): Type + { + return $this->type; + } + + public function hasGetHook(): bool + { + return $this->getHook; + } + + public function hasSetHook(): bool + { + return $this->setHook; + } +} diff --git a/src/Framework/MockObject/Generator/HookedPropertyGenerator.php b/src/Framework/MockObject/Generator/HookedPropertyGenerator.php new file mode 100644 index 00000000000..4fcff6c824d --- /dev/null +++ b/src/Framework/MockObject/Generator/HookedPropertyGenerator.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookedPropertyGenerator +{ + /** + * @param class-string $className + * @param list $properties + */ + public function generate(string $className, array $properties): string + { + $code = ''; + + foreach ($properties as $property) { + $code .= sprintf( + <<<'EOT' + + public %s $%s { +EOT, + $property->type()->asString(), + $property->name(), + ); + + if ($property->hasGetHook()) { + $code .= sprintf( + <<<'EOT' + + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '%s', '$%s::get', [], '%s', $this + ) + ); + } + +EOT, + $className, + $property->name(), + $property->type()->asString(), + ); + } + + if ($property->hasSetHook()) { + $code .= sprintf( + <<<'EOT' + + set (%s $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '%s', '$%s::set', [$value], 'void', $this + ) + ); + } + +EOT, + $property->type()->asString(), + $className, + $property->name(), + ); + } + + $code .= <<<'EOT' + } + +EOT; + } + + return $code; + } +} diff --git a/src/Framework/MockObject/Generator/TemplateLoader.php b/src/Framework/MockObject/Generator/TemplateLoader.php new file mode 100644 index 00000000000..8106ce59cf4 --- /dev/null +++ b/src/Framework/MockObject/Generator/TemplateLoader.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use SebastianBergmann\Template\Template; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait TemplateLoader +{ + /** + * @var array + */ + private static array $templates = []; + + private function loadTemplate(string $template): Template + { + $filename = __DIR__ . '/templates/' . $template; + + if (!isset(self::$templates[$filename])) { + self::$templates[$filename] = new Template($filename); + } + + return self::$templates[$filename]; + } +} diff --git a/src/Framework/MockObject/Generator/templates/deprecation.tpl b/src/Framework/MockObject/Generator/templates/deprecation.tpl new file mode 100644 index 00000000000..5bf06f52de1 --- /dev/null +++ b/src/Framework/MockObject/Generator/templates/deprecation.tpl @@ -0,0 +1,2 @@ + + @trigger_error({deprecation}, E_USER_DEPRECATED); diff --git a/src/Framework/MockObject/Generator/templates/doubled_method.tpl b/src/Framework/MockObject/Generator/templates/doubled_method.tpl new file mode 100644 index 00000000000..bb6fb761d1a --- /dev/null +++ b/src/Framework/MockObject/Generator/templates/doubled_method.tpl @@ -0,0 +1,35 @@ + + {modifier} function {reference}{method_name}({arguments_decl}){return_declaration} + {{deprecation} + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [{arguments_call}]; + $__phpunit_count = func_num_args(); + + if ({arguments_count} !== null && $__phpunit_count > {arguments_count}) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = {arguments_count}; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + '{class_name}', '{method_name}', $__phpunit_arguments, '{return_type}', $this + ) + );{return_result} + } diff --git a/src/Framework/MockObject/Generator/templates/doubled_static_method.tpl b/src/Framework/MockObject/Generator/templates/doubled_static_method.tpl new file mode 100644 index 00000000000..5e5cf23cddd --- /dev/null +++ b/src/Framework/MockObject/Generator/templates/doubled_static_method.tpl @@ -0,0 +1,5 @@ + + {modifier} function {reference}{method_name}({arguments_decl}){return_declaration} + { + throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "{method_name}" cannot be invoked on mock object'); + } diff --git a/src/Framework/MockObject/Generator/templates/intersection.tpl b/src/Framework/MockObject/Generator/templates/intersection.tpl new file mode 100644 index 00000000000..75cd27a6c02 --- /dev/null +++ b/src/Framework/MockObject/Generator/templates/intersection.tpl @@ -0,0 +1,5 @@ +declare(strict_types=1); + +interface {intersection} extends {interfaces} +{ +} diff --git a/src/Framework/MockObject/Generator/templates/test_double_class.tpl b/src/Framework/MockObject/Generator/templates/test_double_class.tpl new file mode 100644 index 00000000000..5d015e3f961 --- /dev/null +++ b/src/Framework/MockObject/Generator/templates/test_double_class.tpl @@ -0,0 +1,5 @@ +declare(strict_types=1); + +{class_declaration} +{ +{use_statements}{property_hooks}{methods}} diff --git a/src/Framework/MockObject/MockBuilder.php b/src/Framework/MockObject/MockBuilder.php new file mode 100644 index 00000000000..67456586e4e --- /dev/null +++ b/src/Framework/MockObject/MockBuilder.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function assert; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use PHPUnit\Framework\MockObject\Generator\RuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; +use PHPUnit\Framework\TestCase; + +/** + * @template MockedType + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MockBuilder extends TestDoubleBuilder +{ + private readonly TestCase $testCase; + + /** + * @var ?class-string + */ + private ?string $mockClassName = null; + + /** + * @param class-string|trait-string $type + */ + public function __construct(TestCase $testCase, string $type) + { + parent::__construct($type); + + $this->testCase = $testCase; + } + + /** + * Creates a mock object using a fluent interface. + * + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidArgumentException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + * + * @return MockedType&MockObject + */ + public function getMock(): MockObject + { + $object = $this->getTestDouble($this->mockClassName, true); + + assert($object instanceof $this->type); + assert($object instanceof MockObject); + + $this->testCase->registerMockObject($this->type, $object); + + return $object; + } + + /** + * Specifies the name for the mock class. + * + * @param class-string $name + * + * @return $this + */ + public function setMockClassName(string $name): self + { + $this->mockClassName = $name; + + return $this; + } +} diff --git a/src/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php b/src/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php new file mode 100644 index 00000000000..4da35c0c176 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/DoubledCloneMethod.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait DoubledCloneMethod +{ + public function __clone(): void + { + $this->__phpunit_state = clone $this->__phpunit_state; + + $this->__phpunit_state()->cloneInvocationHandler(); + } + + abstract public function __phpunit_state(): TestDoubleState; +} diff --git a/src/Framework/MockObject/Runtime/Api/Method.php b/src/Framework/MockObject/Runtime/Api/Method.php new file mode 100644 index 00000000000..c9b4e42e55a --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/Method.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait Method +{ + abstract public function __phpunit_getInvocationHandler(): InvocationHandler; + + public function method(Constraint|PropertyHook|string $constraint): InvocationStubber + { + return $this + ->__phpunit_getInvocationHandler() + ->expects(new AnyInvokedCount) + ->method($constraint); + } +} diff --git a/src/Framework/MockObject/Runtime/Api/MockObjectApi.php b/src/Framework/MockObject/Runtime/Api/MockObjectApi.php new file mode 100644 index 00000000000..a7369567686 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/MockObjectApi.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait MockObjectApi +{ + /** @noinspection MagicMethodsValidityInspection */ + public function __phpunit_hasMatchers(): bool + { + return $this->__phpunit_getInvocationHandler()->hasMatchers(); + } + + /** @noinspection MagicMethodsValidityInspection */ + public function __phpunit_verify(bool $unsetInvocationMocker = true): void + { + $this->__phpunit_getInvocationHandler()->verify(); + + if ($unsetInvocationMocker) { + $this->__phpunit_unsetInvocationMocker(); + } + } + + abstract public function __phpunit_state(): TestDoubleState; + + abstract public function __phpunit_getInvocationHandler(): InvocationHandler; + + abstract public function __phpunit_unsetInvocationMocker(): void; + + public function expects(InvocationOrder $matcher): InvocationStubber + { + return $this->__phpunit_getInvocationHandler()->expects($matcher); + } +} diff --git a/src/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php b/src/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php new file mode 100644 index 00000000000..88797884d77 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/ProxiedCloneMethod.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait ProxiedCloneMethod +{ + public function __clone(): void + { + $this->__phpunit_state = clone $this->__phpunit_state; + + $this->__phpunit_state()->cloneInvocationHandler(); + + parent::__clone(); + } + + abstract public function __phpunit_state(): TestDoubleState; +} diff --git a/src/Framework/MockObject/Runtime/Api/StubApi.php b/src/Framework/MockObject/Runtime/Api/StubApi.php new file mode 100644 index 00000000000..faba8d40fbb --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/StubApi.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This trait is not covered by the backward compatibility promise for PHPUnit + */ +trait StubApi +{ + private readonly TestDoubleState $__phpunit_state; + + public function __phpunit_state(): TestDoubleState + { + return $this->__phpunit_state; + } + + /** @noinspection MagicMethodsValidityInspection */ + public function __phpunit_getInvocationHandler(): InvocationHandler + { + return $this->__phpunit_state()->invocationHandler(); + } + + /** @noinspection MagicMethodsValidityInspection */ + public function __phpunit_unsetInvocationMocker(): void + { + $this->__phpunit_state()->unsetInvocationHandler(); + } +} diff --git a/src/Framework/MockObject/Runtime/Api/TestDoubleState.php b/src/Framework/MockObject/Runtime/Api/TestDoubleState.php new file mode 100644 index 00000000000..93b10c14da5 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Api/TestDoubleState.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDoubleState +{ + /** + * @var list + */ + private readonly array $configurableMethods; + private readonly bool $generateReturnValues; + private ?InvocationHandler $invocationHandler = null; + + /** + * @param list $configurableMethods + */ + public function __construct(array $configurableMethods, bool $generateReturnValues) + { + $this->configurableMethods = $configurableMethods; + $this->generateReturnValues = $generateReturnValues; + } + + public function invocationHandler(): InvocationHandler + { + if ($this->invocationHandler !== null) { + return $this->invocationHandler; + } + + $this->invocationHandler = new InvocationHandler( + $this->configurableMethods, + $this->generateReturnValues, + ); + + return $this->invocationHandler; + } + + public function cloneInvocationHandler(): void + { + if ($this->invocationHandler === null) { + return; + } + + $this->invocationHandler = clone $this->invocationHandler; + } + + public function unsetInvocationHandler(): void + { + $this->invocationHandler = null; + } + + /** + * @return list + */ + public function configurableMethods(): array + { + return $this->configurableMethods; + } + + public function generateReturnValues(): bool + { + return $this->generateReturnValues; + } +} diff --git a/src/Framework/MockObject/Runtime/Interface/InvocationStubber.php b/src/Framework/MockObject/Runtime/Interface/InvocationStubber.php new file mode 100644 index 00000000000..337c82fb3f3 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Interface/InvocationStubber.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\MockObject\Stub\Stub; +use Throwable; + +interface InvocationStubber +{ + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param Constraint|non-empty-string|PropertyHook $constraint + * + * @return $this + */ + public function method(Constraint|PropertyHook|string $constraint): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param non-empty-string $id + * + * @return $this + */ + public function id(string $id): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param non-empty-string $id + * + * @return $this + */ + public function after(string $id): self; + + /** + * @return $this + */ + public function with(mixed ...$arguments): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function withAnyParameters(): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function will(Stub $stub): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturn(mixed $value, mixed ...$nextValues): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnReference(mixed &$reference): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @param array> $valueMap + * + * @return $this + */ + public function willReturnMap(array $valueMap): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnArgument(int $argumentIndex): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnCallback(callable $callback): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnSelf(): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willReturnOnConsecutiveCalls(mixed ...$values): self; + + /** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @return $this + */ + public function willThrowException(Throwable $exception): self; +} diff --git a/src/Framework/MockObject/Runtime/Interface/MockObject.php b/src/Framework/MockObject/Runtime/Interface/MockObject.php new file mode 100644 index 00000000000..0ddc46dc4fe --- /dev/null +++ b/src/Framework/MockObject/Runtime/Interface/MockObject.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface MockObject extends Stub +{ + public function expects(InvocationOrder $invocationRule): InvocationStubber; +} diff --git a/src/Framework/MockObject/Runtime/Interface/MockObjectInternal.php b/src/Framework/MockObject/Runtime/Interface/MockObjectInternal.php new file mode 100644 index 00000000000..167d2466db4 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Interface/MockObjectInternal.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface MockObjectInternal extends MockObject, StubInternal +{ + public function __phpunit_hasMatchers(): bool; + + public function __phpunit_verify(bool $unsetInvocationMocker = true): void; +} diff --git a/src/Framework/MockObject/Runtime/Interface/Stub.php b/src/Framework/MockObject/Runtime/Interface/Stub.php new file mode 100644 index 00000000000..6321c98bb39 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Interface/Stub.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Stub +{ + public function method(Constraint|PropertyHook|string $constraint): InvocationStubber; +} diff --git a/src/Framework/MockObject/Runtime/Interface/StubInternal.php b/src/Framework/MockObject/Runtime/Interface/StubInternal.php new file mode 100644 index 00000000000..6e428ea5ea1 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Interface/StubInternal.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface StubInternal extends Stub +{ + public function __phpunit_state(): TestDoubleState; + + public function __phpunit_getInvocationHandler(): InvocationHandler; + + public function __phpunit_unsetInvocationMocker(): void; +} diff --git a/src/Framework/MockObject/Runtime/Invocation.php b/src/Framework/MockObject/Runtime/Invocation.php new file mode 100644 index 00000000000..d9e3c3f66ff --- /dev/null +++ b/src/Framework/MockObject/Runtime/Invocation.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_map; +use function implode; +use function sprintf; +use function str_starts_with; +use function strtolower; +use function substr; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Util\Exporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Invocation implements SelfDescribing +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @var array + */ + private array $parameters; + private string $returnType; + private bool $isReturnTypeNullable; + private MockObjectInternal|StubInternal $object; + + /** + * @param class-string $className + * @param non-empty-string $methodName + * @param array $parameters + */ + public function __construct(string $className, string $methodName, array $parameters, string $returnType, MockObjectInternal|StubInternal $object) + { + $this->className = $className; + $this->methodName = $methodName; + $this->parameters = $parameters; + $this->object = $object; + + if (strtolower($methodName) === '__tostring') { + $returnType = 'string'; + } + + if (str_starts_with($returnType, '?')) { + $returnType = substr($returnType, 1); + $this->isReturnTypeNullable = true; + } else { + $this->isReturnTypeNullable = false; + } + + $this->returnType = $returnType; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } + + /** + * @throws Exception + */ + public function generateReturnValue(): mixed + { + if ($this->returnType === 'never') { + throw new NeverReturningMethodException( + $this->className, + $this->methodName, + ); + } + + if ($this->isReturnTypeNullable) { + return null; + } + + return (new ReturnValueGenerator)->generate( + $this->className, + $this->methodName, + $this->object, + $this->returnType, + ); + } + + public function toString(): string + { + return sprintf( + '%s::%s(%s)%s', + $this->className, + $this->methodName, + implode( + ', ', + array_map( + [Exporter::class, 'shortenedExport'], + $this->parameters, + ), + ), + $this->returnType !== '' ? sprintf(': %s', $this->returnType) : '', + ); + } + + public function object(): MockObjectInternal|StubInternal + { + return $this->object; + } +} diff --git a/src/Framework/MockObject/Runtime/InvocationHandler.php b/src/Framework/MockObject/Runtime/InvocationHandler.php new file mode 100644 index 00000000000..13074df5ef7 --- /dev/null +++ b/src/Framework/MockObject/Runtime/InvocationHandler.php @@ -0,0 +1,155 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_any; +use function strtolower; +use Exception; +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvocationHandler +{ + /** + * @var list + */ + private array $matchers = []; + + /** + * @var array + */ + private array $matcherMap = []; + + /** + * @var list + */ + private readonly array $configurableMethods; + private readonly bool $returnValueGeneration; + + /** + * @param list $configurableMethods + */ + public function __construct(array $configurableMethods, bool $returnValueGeneration) + { + $this->configurableMethods = $configurableMethods; + $this->returnValueGeneration = $returnValueGeneration; + } + + public function hasMatchers(): bool + { + return array_any( + $this->matchers, + static fn (Matcher $matcher) => $matcher->hasMatchers(), + ); + } + + /** + * Looks up the match builder with identification $id and returns it. + * + * @param non-empty-string $id + */ + public function lookupMatcher(string $id): ?Matcher + { + return $this->matcherMap[$id] ?? null; + } + + /** + * Registers a matcher with the identification $id. The matcher can later be + * looked up using lookupMatcher() to figure out if it has been invoked. + * + * @param non-empty-string $id + * + * @throws MatcherAlreadyRegisteredException + */ + public function registerMatcher(string $id, Matcher $matcher): void + { + if (isset($this->matcherMap[$id])) { + throw new MatcherAlreadyRegisteredException($id); + } + + $this->matcherMap[$id] = $matcher; + } + + public function expects(InvocationOrder $rule): InvocationStubber + { + $matcher = new Matcher($rule); + $this->addMatcher($matcher); + + return new InvocationStubberImplementation( + $this, + $matcher, + ...$this->configurableMethods, + ); + } + + /** + * @throws \PHPUnit\Framework\MockObject\Exception + * @throws Exception + */ + public function invoke(Invocation $invocation): mixed + { + $exception = null; + $hasReturnValue = false; + $returnValue = null; + + foreach ($this->matchers as $match) { + try { + if ($match->matches($invocation)) { + $value = $match->invoked($invocation); + + if (!$hasReturnValue) { + $returnValue = $value; + $hasReturnValue = true; + } + } + } catch (Exception $e) { + $exception = $e; + } + } + + if ($exception !== null) { + throw $exception; + } + + if ($hasReturnValue) { + return $returnValue; + } + + if (!$this->returnValueGeneration) { + if (strtolower($invocation->methodName()) === '__tostring') { + return ''; + } + + throw new ReturnValueNotConfiguredException($invocation); + } + + return $invocation->generateReturnValue(); + } + + /** + * @throws Throwable + */ + public function verify(): void + { + foreach ($this->matchers as $matcher) { + $matcher->verify(); + } + } + + private function addMatcher(Matcher $matcher): void + { + $this->matchers[] = $matcher; + } +} diff --git a/src/Framework/MockObject/Runtime/InvocationStubberImplementation.php b/src/Framework/MockObject/Runtime/InvocationStubberImplementation.php new file mode 100644 index 00000000000..3aca45a294b --- /dev/null +++ b/src/Framework/MockObject/Runtime/InvocationStubberImplementation.php @@ -0,0 +1,330 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_flip; +use function array_key_exists; +use function array_map; +use function array_merge; +use function array_pop; +use function assert; +use function count; +use function is_string; +use function range; +use function strtolower; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\MockObject\Stub\ConsecutiveCalls; +use PHPUnit\Framework\MockObject\Stub\Exception; +use PHPUnit\Framework\MockObject\Stub\ReturnArgument; +use PHPUnit\Framework\MockObject\Stub\ReturnCallback; +use PHPUnit\Framework\MockObject\Stub\ReturnReference; +use PHPUnit\Framework\MockObject\Stub\ReturnSelf; +use PHPUnit\Framework\MockObject\Stub\ReturnStub; +use PHPUnit\Framework\MockObject\Stub\ReturnValueMap; +use PHPUnit\Framework\MockObject\Stub\Stub; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvocationStubberImplementation implements InvocationStubber +{ + private readonly InvocationHandler $invocationHandler; + private readonly Matcher $matcher; + + /** + * @var list + */ + private readonly array $configurableMethods; + + /** + * @var ?array + */ + private ?array $configurableMethodNames = null; + + public function __construct(InvocationHandler $handler, Matcher $matcher, ConfigurableMethod ...$configurableMethods) + { + $this->invocationHandler = $handler; + $this->matcher = $matcher; + $this->configurableMethods = $configurableMethods; + } + + /** + * @param Constraint|non-empty-string|PropertyHook $constraint + * + * @throws InvalidArgumentException + * @throws MethodCannotBeConfiguredException + * @throws MethodNameAlreadyConfiguredException + * + * @return $this + */ + public function method(Constraint|PropertyHook|string $constraint): InvocationStubber + { + if ($this->matcher->hasMethodNameRule()) { + throw new MethodNameAlreadyConfiguredException; + } + + if ($constraint instanceof PropertyHook) { + $constraint = $constraint->asString(); + } + + if (is_string($constraint)) { + $this->configurableMethodNames ??= array_flip( + array_map( + static fn (ConfigurableMethod $configurable) => strtolower($configurable->name()), + $this->configurableMethods, + ), + ); + + if (!array_key_exists(strtolower($constraint), $this->configurableMethodNames)) { + throw new MethodCannotBeConfiguredException($constraint); + } + } + + $this->matcher->setMethodNameRule(new Rule\MethodName($constraint)); + + return $this; + } + + /** + * @param non-empty-string $id + * + * @throws MatcherAlreadyRegisteredException + * + * @return $this + */ + public function id(string $id): InvocationStubber + { + $this->invocationHandler->registerMatcher($id, $this->matcher); + + return $this; + } + + /** + * @param non-empty-string $id + * + * @return $this + */ + public function after(string $id): InvocationStubber + { + $this->matcher->setAfterMatchBuilderId($id); + + return $this; + } + + /** + * @throws \PHPUnit\Framework\Exception + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + * + * @return $this + */ + public function with(mixed ...$arguments): InvocationStubber + { + $this->ensureParametersCanBeConfigured(); + + $this->matcher->setParametersRule(new Rule\Parameters($arguments)); + + return $this; + } + + /** + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + * + * @return $this + */ + public function withAnyParameters(): InvocationStubber + { + $this->ensureParametersCanBeConfigured(); + + $this->matcher->setParametersRule(new Rule\AnyParameters); + + return $this; + } + + /** + * @return $this + */ + public function will(Stub $stub): InvocationStubber + { + $this->matcher->setStub($stub); + + return $this; + } + + /** + * @throws IncompatibleReturnValueException + */ + public function willReturn(mixed $value, mixed ...$nextValues): InvocationStubber + { + if (count($nextValues) === 0) { + $this->ensureTypeOfReturnValues([$value]); + + $stub = $value instanceof Stub ? $value : new ReturnStub($value); + + return $this->will($stub); + } + + $values = array_merge([$value], $nextValues); + + $this->ensureTypeOfReturnValues($values); + + $stub = new ConsecutiveCalls($values); + + return $this->will($stub); + } + + public function willReturnReference(mixed &$reference): InvocationStubber + { + $stub = new ReturnReference($reference); + + return $this->will($stub); + } + + public function willReturnMap(array $valueMap): InvocationStubber + { + $method = $this->configuredMethod(); + + assert($method instanceof ConfigurableMethod); + + $numberOfParameters = $method->numberOfParameters(); + $defaultValues = $method->defaultParameterValues(); + $hasDefaultValues = $defaultValues !== []; + + $_valueMap = []; + + foreach ($valueMap as $mapping) { + $numberOfConfiguredParameters = count($mapping) - 1; + + if ($numberOfConfiguredParameters === $numberOfParameters || !$hasDefaultValues) { + $_valueMap[] = $mapping; + + continue; + } + + $_mapping = []; + $returnValue = array_pop($mapping); + + foreach (range(0, $numberOfParameters - 1) as $i) { + if (array_key_exists($i, $mapping)) { + $_mapping[] = $mapping[$i]; + + continue; + } + + if (array_key_exists($i, $defaultValues)) { + $_mapping[] = $defaultValues[$i]; + } + } + + $_mapping[] = $returnValue; + $_valueMap[] = $_mapping; + } + + $stub = new ReturnValueMap($_valueMap); + + return $this->will($stub); + } + + public function willReturnArgument(int $argumentIndex): InvocationStubber + { + $stub = new ReturnArgument($argumentIndex); + + return $this->will($stub); + } + + public function willReturnCallback(callable $callback): InvocationStubber + { + $stub = new ReturnCallback($callback); + + return $this->will($stub); + } + + public function willReturnSelf(): InvocationStubber + { + $stub = new ReturnSelf; + + return $this->will($stub); + } + + public function willReturnOnConsecutiveCalls(mixed ...$values): InvocationStubber + { + $stub = new ConsecutiveCalls($values); + + return $this->will($stub); + } + + public function willThrowException(Throwable $exception): InvocationStubber + { + $stub = new Exception($exception); + + return $this->will($stub); + } + + /** + * @throws MethodNameNotConfiguredException + * @throws MethodParametersAlreadyConfiguredException + */ + private function ensureParametersCanBeConfigured(): void + { + if (!$this->matcher->hasMethodNameRule()) { + throw new MethodNameNotConfiguredException; + } + + if ($this->matcher->hasParametersRule()) { + throw new MethodParametersAlreadyConfiguredException; + } + } + + private function configuredMethod(): ?ConfigurableMethod + { + $configuredMethod = null; + + foreach ($this->configurableMethods as $configurableMethod) { + if ($this->matcher->methodNameRule()->matchesName($configurableMethod->name())) { + if ($configuredMethod !== null) { + return null; + } + + $configuredMethod = $configurableMethod; + } + } + + return $configuredMethod; + } + + /** + * @param array $values + * + * @throws IncompatibleReturnValueException + */ + private function ensureTypeOfReturnValues(array $values): void + { + $configuredMethod = $this->configuredMethod(); + + if ($configuredMethod === null) { + return; + } + + foreach ($values as $value) { + if (!$configuredMethod->mayReturn($value)) { + throw new IncompatibleReturnValueException( + $configuredMethod, + $value, + ); + } + } + } +} diff --git a/src/Framework/MockObject/Runtime/Matcher.php b/src/Framework/MockObject/Runtime/Matcher.php new file mode 100644 index 00000000000..f1587f3b3f1 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Matcher.php @@ -0,0 +1,219 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount; +use PHPUnit\Framework\MockObject\Rule\AnyParameters; +use PHPUnit\Framework\MockObject\Rule\InvocationOrder; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount; +use PHPUnit\Framework\MockObject\Rule\InvokedCount; +use PHPUnit\Framework\MockObject\Rule\MethodName; +use PHPUnit\Framework\MockObject\Rule\ParametersRule; +use PHPUnit\Framework\MockObject\Stub\Stub; +use PHPUnit\Util\ThrowableToStringMapper; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Matcher +{ + private readonly InvocationOrder $invocationRule; + + /** + * @var ?non-empty-string + */ + private ?string $afterMatchBuilderId = null; + private ?MethodName $methodNameRule = null; + private ?ParametersRule $parametersRule = null; + private ?Stub $stub = null; + + public function __construct(InvocationOrder $rule) + { + $this->invocationRule = $rule; + } + + public function hasMatchers(): bool + { + return !$this->invocationRule instanceof AnyInvokedCount; + } + + public function hasMethodNameRule(): bool + { + return $this->methodNameRule !== null; + } + + public function methodNameRule(): MethodName + { + return $this->methodNameRule; + } + + public function setMethodNameRule(MethodName $rule): void + { + $this->methodNameRule = $rule; + } + + public function hasParametersRule(): bool + { + return $this->parametersRule !== null; + } + + public function setParametersRule(ParametersRule $rule): void + { + $this->parametersRule = $rule; + } + + public function setStub(Stub $stub): void + { + $this->stub = $stub; + } + + /** + * @param non-empty-string $id + */ + public function setAfterMatchBuilderId(string $id): void + { + $this->afterMatchBuilderId = $id; + } + + /** + * @throws Exception + * @throws ExpectationFailedException + * @throws MatchBuilderNotFoundException + * @throws MethodNameNotConfiguredException + * @throws RuntimeException + */ + public function invoked(Invocation $invocation): mixed + { + if ($this->methodNameRule === null) { + throw new MethodNameNotConfiguredException; + } + + if ($this->afterMatchBuilderId !== null) { + $matcher = $invocation->object() + ->__phpunit_getInvocationHandler() + ->lookupMatcher($this->afterMatchBuilderId); + + if ($matcher === null) { + throw new MatchBuilderNotFoundException($this->afterMatchBuilderId); + } + } + + $this->invocationRule->invoked($invocation); + + try { + $this->parametersRule?->apply($invocation); + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s\n%s", + $this->methodNameRule->toString(), + $this->invocationRule->toString(), + $e->getMessage(), + ), + $e->getComparisonFailure(), + ); + } + + if ($this->stub !== null) { + return $this->stub->invoke($invocation); + } + + return $invocation->generateReturnValue(); + } + + /** + * @throws ExpectationFailedException + * @throws MatchBuilderNotFoundException + * @throws MethodNameNotConfiguredException + * @throws RuntimeException + */ + public function matches(Invocation $invocation): bool + { + if ($this->afterMatchBuilderId !== null) { + $matcher = $invocation->object() + ->__phpunit_getInvocationHandler() + ->lookupMatcher($this->afterMatchBuilderId); + + if ($matcher === null) { + throw new MatchBuilderNotFoundException($this->afterMatchBuilderId); + } + + if (!$matcher->invocationRule->hasBeenInvoked()) { + return false; + } + } + + if ($this->methodNameRule === null) { + throw new MethodNameNotConfiguredException; + } + + if (!$this->invocationRule->matches($invocation)) { + return false; + } + + try { + if (!$this->methodNameRule->matches($invocation)) { + return false; + } + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s\n%s", + $this->methodNameRule->toString(), + $this->invocationRule->toString(), + $e->getMessage(), + ), + $e->getComparisonFailure(), + ); + } + + return true; + } + + /** + * @throws ExpectationFailedException + * @throws MethodNameNotConfiguredException + */ + public function verify(): void + { + if ($this->methodNameRule === null) { + throw new MethodNameNotConfiguredException; + } + + try { + $this->invocationRule->verify(); + + if ($this->parametersRule === null) { + $this->parametersRule = new AnyParameters; + } + + $invocationIsAny = $this->invocationRule instanceof AnyInvokedCount; + $invocationIsNever = $this->invocationRule instanceof InvokedCount && $this->invocationRule->isNever(); + $invocationIsAtMost = $this->invocationRule instanceof InvokedAtMostCount; + + if (!$invocationIsAny && !$invocationIsNever && !$invocationIsAtMost) { + $this->parametersRule->verify(); + } + } catch (ExpectationFailedException $e) { + throw new ExpectationFailedException( + sprintf( + "Expectation failed for %s when %s.\n%s", + $this->methodNameRule->toString(), + $this->invocationRule->toString(), + ThrowableToStringMapper::map($e), + ), + ); + } + } +} diff --git a/src/Framework/MockObject/Runtime/MethodNameConstraint.php b/src/Framework/MockObject/Runtime/MethodNameConstraint.php new file mode 100644 index 00000000000..bb6bf60bdde --- /dev/null +++ b/src/Framework/MockObject/Runtime/MethodNameConstraint.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use function strtolower; +use PHPUnit\Framework\Constraint\Constraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MethodNameConstraint extends Constraint +{ + private string $methodName; + + public function __construct(string $methodName) + { + $this->methodName = $methodName; + } + + public function toString(): string + { + return sprintf( + 'is "%s"', + $this->methodName, + ); + } + + protected function matches(mixed $other): bool + { + return strtolower($this->methodName) === strtolower((string) $other); + } +} diff --git a/src/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php b/src/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php new file mode 100644 index 00000000000..14266f55731 --- /dev/null +++ b/src/Framework/MockObject/Runtime/PropertyHook/PropertyGetHook.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PropertyGetHook extends PropertyHook +{ + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function asString(): string + { + return sprintf( + '$%s::get', + $this->propertyName(), + ); + } +} diff --git a/src/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php b/src/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php new file mode 100644 index 00000000000..a7664f8ed76 --- /dev/null +++ b/src/Framework/MockObject/Runtime/PropertyHook/PropertyHook.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class PropertyHook +{ + /** + * @var non-empty-string + */ + private string $propertyName; + + /** + * @param non-empty-string $propertyName + */ + public static function get(string $propertyName): PropertyGetHook + { + return new PropertyGetHook($propertyName); + } + + /** + * @param non-empty-string $propertyName + */ + public static function set(string $propertyName): PropertySetHook + { + return new PropertySetHook($propertyName); + } + + /** + * @param non-empty-string $propertyName + */ + protected function __construct(string $propertyName) + { + $this->propertyName = $propertyName; + } + + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } + + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + abstract public function asString(): string; +} diff --git a/src/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php b/src/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php new file mode 100644 index 00000000000..7d4918eb7c6 --- /dev/null +++ b/src/Framework/MockObject/Runtime/PropertyHook/PropertySetHook.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PropertySetHook extends PropertyHook +{ + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function asString(): string + { + return sprintf( + '$%s::set', + $this->propertyName(), + ); + } +} diff --git a/src/Framework/MockObject/Runtime/ReturnValueGenerator.php b/src/Framework/MockObject/Runtime/ReturnValueGenerator.php new file mode 100644 index 00000000000..f28dfacc3c8 --- /dev/null +++ b/src/Framework/MockObject/Runtime/ReturnValueGenerator.php @@ -0,0 +1,259 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_map; +use function explode; +use function in_array; +use function interface_exists; +use function sprintf; +use function str_contains; +use function str_ends_with; +use function str_starts_with; +use function substr; +use PHPUnit\Framework\MockObject\Generator\Generator; +use ReflectionClass; +use ReflectionObject; +use stdClass; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnValueGenerator +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws Exception + */ + public function generate(string $className, string $methodName, StubInternal $testStub, string $returnType): mixed + { + $intersection = false; + $union = false; + + if (str_contains($returnType, '|')) { + $types = explode('|', $returnType); + $union = true; + + foreach ($types as $key => $type) { + if (str_starts_with($type, '(') && str_ends_with($type, ')')) { + $types[$key] = substr($type, 1, -1); + } + } + } elseif (str_contains($returnType, '&')) { + $types = explode('&', $returnType); + $intersection = true; + } else { + $types = [$returnType]; + } + + if (!$intersection) { + $lowerTypes = array_map('strtolower', $types); + + if (in_array('', $lowerTypes, true) || + in_array('null', $lowerTypes, true) || + in_array('mixed', $lowerTypes, true) || + in_array('void', $lowerTypes, true)) { + return null; + } + + if (in_array('true', $lowerTypes, true)) { + return true; + } + + if (in_array('false', $lowerTypes, true) || + in_array('bool', $lowerTypes, true)) { + return false; + } + + if (in_array('float', $lowerTypes, true)) { + return 0.0; + } + + if (in_array('int', $lowerTypes, true)) { + return 0; + } + + if (in_array('string', $lowerTypes, true)) { + return ''; + } + + if (in_array('array', $lowerTypes, true)) { + return []; + } + + if (in_array('static', $lowerTypes, true)) { + return $this->newInstanceOf($testStub, $className, $methodName); + } + + if (in_array('object', $lowerTypes, true)) { + return new stdClass; + } + + if (in_array('callable', $lowerTypes, true) || + in_array('closure', $lowerTypes, true)) { + return static function (): void + { + }; + } + + if (in_array('traversable', $lowerTypes, true) || + in_array('generator', $lowerTypes, true) || + in_array('iterable', $lowerTypes, true)) { + $generator = static function (): \Generator + { + yield from []; + }; + + return $generator(); + } + + if (!$union) { + return $this->testDoubleFor($returnType, $className, $methodName); + } + } + + if ($union) { + foreach ($types as $type) { + if (str_contains($type, '&')) { + $_types = explode('&', $type); + + if ($this->onlyInterfaces($_types)) { + return $this->testDoubleForIntersectionOfInterfaces($_types, $className, $methodName); + } + } + } + } + + if ($intersection && $this->onlyInterfaces($types)) { + return $this->testDoubleForIntersectionOfInterfaces($types, $className, $methodName); + } + + $reason = ''; + + if ($union) { + $reason = ' because the declared return type is a union'; + } elseif ($intersection) { + $reason = ' because the declared return type is an intersection'; + } + + throw new RuntimeException( + sprintf( + 'Return value for %s::%s() cannot be generated%s, please configure a return value for this method', + $className, + $methodName, + $reason, + ), + ); + } + + /** + * @param non-empty-list $types + */ + private function onlyInterfaces(array $types): bool + { + foreach ($types as $type) { + if (!interface_exists($type)) { + return false; + } + } + + return true; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function newInstanceOf(StubInternal $testStub, string $className, string $methodName): Stub + { + try { + $object = new ReflectionClass($testStub::class)->newInstanceWithoutConstructor(); + $reflector = new ReflectionObject($object); + + $reflector->getProperty('__phpunit_state')->setValue( + $object, + new TestDoubleState( + $testStub->__phpunit_state()->configurableMethods(), + $testStub->__phpunit_state()->generateReturnValues(), + ), + ); + + return $object; + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new RuntimeException( + sprintf( + 'Return value for %s::%s() cannot be generated: %s', + $className, + $methodName, + $t->getMessage(), + ), + ); + // @codeCoverageIgnoreEnd + } + } + + /** + * @param class-string $type + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function testDoubleFor(string $type, string $className, string $methodName): Stub + { + try { + return (new Generator)->testDouble($type, false, [], [], '', false); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new RuntimeException( + sprintf( + 'Return value for %s::%s() cannot be generated: %s', + $className, + $methodName, + $t->getMessage(), + ), + ); + // @codeCoverageIgnoreEnd + } + } + + /** + * @param non-empty-list $types + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws RuntimeException + */ + private function testDoubleForIntersectionOfInterfaces(array $types, string $className, string $methodName): Stub + { + try { + return (new Generator)->testDoubleForInterfaceIntersection($types, false); + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + throw new RuntimeException( + sprintf( + 'Return value for %s::%s() cannot be generated: %s', + $className, + $methodName, + $t->getMessage(), + ), + ); + // @codeCoverageIgnoreEnd + } + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/AnyInvokedCount.php b/src/Framework/MockObject/Runtime/Rule/AnyInvokedCount.php new file mode 100644 index 00000000000..382f9308116 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/AnyInvokedCount.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class AnyInvokedCount extends InvocationOrder +{ + public function toString(): string + { + return 'invoked zero or more times'; + } + + public function verify(): void + { + } + + public function matches(BaseInvocation $invocation): bool + { + return true; + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/AnyParameters.php b/src/Framework/MockObject/Runtime/Rule/AnyParameters.php new file mode 100644 index 00000000000..0bca009951a --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/AnyParameters.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class AnyParameters implements ParametersRule +{ + /** + * @throws void + */ + public function apply(BaseInvocation $invocation): void + { + } + + public function verify(): void + { + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/InvocationOrder.php b/src/Framework/MockObject/Runtime/Rule/InvocationOrder.php new file mode 100644 index 00000000000..c3fb8f29d83 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/InvocationOrder.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function count; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\SelfDescribing; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class InvocationOrder implements SelfDescribing +{ + /** + * @var list + */ + private array $invocations = []; + + public function numberOfInvocations(): int + { + return count($this->invocations); + } + + public function hasBeenInvoked(): bool + { + return count($this->invocations) > 0; + } + + final public function invoked(BaseInvocation $invocation): void + { + $this->invocations[] = $invocation; + + $this->invokedDo($invocation); + } + + abstract public function matches(BaseInvocation $invocation): bool; + + abstract public function verify(): void; + + protected function invokedDo(BaseInvocation $invocation): void + { + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php b/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php new file mode 100644 index 00000000000..a78d933d194 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastCount.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtLeastCount extends InvocationOrder +{ + private readonly int $requiredInvocations; + + public function __construct(int $requiredInvocations) + { + $this->requiredInvocations = $requiredInvocations; + } + + public function toString(): string + { + return sprintf( + 'invoked at least %d time%s', + $this->requiredInvocations, + $this->requiredInvocations !== 1 ? 's' : '', + ); + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualInvocations = $this->numberOfInvocations(); + + if ($actualInvocations < $this->requiredInvocations) { + throw new ExpectationFailedException( + sprintf( + 'Expected invocation at least %d time%s but it occurred %d time%s.', + $this->requiredInvocations, + $this->requiredInvocations !== 1 ? 's' : '', + $actualInvocations, + $actualInvocations !== 1 ? 's' : '', + ), + ); + } + } + + public function matches(BaseInvocation $invocation): bool + { + return true; + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.php b/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.php new file mode 100644 index 00000000000..91026f53d3f --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/InvokedAtLeastOnce.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtLeastOnce extends InvocationOrder +{ + public function toString(): string + { + return 'invoked at least once'; + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $count = $this->numberOfInvocations(); + + if ($count < 1) { + throw new ExpectationFailedException( + 'Expected invocation at least once but it never occurred.', + ); + } + } + + public function matches(BaseInvocation $invocation): bool + { + return true; + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php b/src/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php new file mode 100644 index 00000000000..0cfda5e182d --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/InvokedAtMostCount.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedAtMostCount extends InvocationOrder +{ + private readonly int $allowedInvocations; + + public function __construct(int $allowedInvocations) + { + $this->allowedInvocations = $allowedInvocations; + } + + public function toString(): string + { + return sprintf( + 'invoked at most %d time%s', + $this->allowedInvocations, + $this->allowedInvocations !== 1 ? 's' : '', + ); + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualInvocations = $this->numberOfInvocations(); + + if ($actualInvocations > $this->allowedInvocations) { + throw new ExpectationFailedException( + sprintf( + 'Expected invocation at most %d time%s but it occurred %d time%s.', + $this->allowedInvocations, + $this->allowedInvocations !== 1 ? 's' : '', + $actualInvocations, + $actualInvocations !== 1 ? 's' : '', + ), + ); + } + } + + public function matches(BaseInvocation $invocation): bool + { + return true; + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/InvokedCount.php b/src/Framework/MockObject/Runtime/Rule/InvokedCount.php new file mode 100644 index 00000000000..3f0e505a0db --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/InvokedCount.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function sprintf; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvokedCount extends InvocationOrder +{ + private readonly int $expectedCount; + + public function __construct(int $expectedCount) + { + $this->expectedCount = $expectedCount; + } + + public function isNever(): bool + { + return $this->expectedCount === 0; + } + + public function toString(): string + { + return sprintf( + 'invoked %d time%s', + $this->expectedCount, + $this->expectedCount !== 1 ? 's' : '', + ); + } + + public function matches(BaseInvocation $invocation): bool + { + return true; + } + + /** + * Verifies that the current expectation is valid. If everything is OK the + * code should just return, if not it must throw an exception. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $actualCount = $this->numberOfInvocations(); + + if ($actualCount !== $this->expectedCount) { + throw new ExpectationFailedException( + sprintf( + 'Method was expected to be called %d time%s, actually called %d time%s.', + $this->expectedCount, + $this->expectedCount !== 1 ? 's' : '', + $actualCount, + $actualCount !== 1 ? 's' : '', + ), + ); + } + } + + /** + * @throws ExpectationFailedException + */ + protected function invokedDo(BaseInvocation $invocation): void + { + $count = $this->numberOfInvocations(); + + if ($count > $this->expectedCount) { + $message = $invocation->toString() . ' '; + + $message .= match ($this->expectedCount) { + 0 => 'was not expected to be called.', + 1 => 'was not expected to be called more than once.', + default => sprintf( + 'was not expected to be called more than %d times.', + $this->expectedCount, + ), + }; + + throw new ExpectationFailedException($message); + } + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/MethodName.php b/src/Framework/MockObject/Runtime/Rule/MethodName.php new file mode 100644 index 00000000000..219a8087d8d --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/MethodName.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function is_string; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Framework\MockObject\MethodNameConstraint; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MethodName +{ + private Constraint $constraint; + + /** + * @throws InvalidArgumentException + */ + public function __construct(Constraint|string $constraint) + { + if (is_string($constraint)) { + $constraint = new MethodNameConstraint($constraint); + } + + $this->constraint = $constraint; + } + + public function toString(): string + { + return 'method name ' . $this->constraint->toString(); + } + + /** + * @throws ExpectationFailedException + */ + public function matches(BaseInvocation $invocation): bool + { + return $this->matchesName($invocation->methodName()); + } + + /** + * @throws ExpectationFailedException + */ + public function matchesName(string $methodName): bool + { + return (bool) $this->constraint->evaluate($methodName, '', true); + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/Parameters.php b/src/Framework/MockObject/Runtime/Rule/Parameters.php new file mode 100644 index 00000000000..17df3f0a73a --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/Parameters.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use function count; +use function sprintf; +use Exception; +use PHPUnit\Framework\Constraint\Callback; +use PHPUnit\Framework\Constraint\Constraint; +use PHPUnit\Framework\Constraint\IsAnything; +use PHPUnit\Framework\Constraint\IsEqual; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; +use PHPUnit\Util\Test; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Parameters implements ParametersRule +{ + /** + * @var list + */ + private array $parameters = []; + private ?BaseInvocation $invocation = null; + private null|bool|ExpectationFailedException $parameterVerificationResult; + + /** + * @param array $parameters + * + * @throws \PHPUnit\Framework\Exception + */ + public function __construct(array $parameters) + { + foreach ($parameters as $parameter) { + if (!$parameter instanceof Constraint) { + $parameter = new IsEqual( + $parameter, + ); + } + + $this->parameters[] = $parameter; + } + } + + /** + * @throws Exception + */ + public function apply(BaseInvocation $invocation): void + { + $this->invocation = $invocation; + $this->parameterVerificationResult = null; + + try { + $this->parameterVerificationResult = $this->doVerify(); + } catch (ExpectationFailedException $e) { + $this->parameterVerificationResult = $e; + + throw $this->parameterVerificationResult; + } + } + + /** + * Checks if the invocation $invocation matches the current rules. If it + * does the rule will get the invoked() method called which should check + * if an expectation is met. + * + * @throws ExpectationFailedException + */ + public function verify(): void + { + $this->doVerify(); + } + + /** + * @throws ExpectationFailedException + */ + private function doVerify(): bool + { + if (isset($this->parameterVerificationResult)) { + return $this->guardAgainstDuplicateEvaluationOfParameterConstraints(); + } + + if ($this->invocation === null) { + throw new ExpectationFailedException('Doubled method does not exist.'); + } + + if (count($this->invocation->parameters()) < count($this->parameters)) { + $message = 'Parameter count for invocation %s is too low.'; + + // The user called `->with($this->anything())`, but may have meant + // `->withAnyParameters()`. + // + // @see https://github.com/sebastianbergmann/phpunit-mock-objects/issues/199 + if (count($this->parameters) === 1 && + $this->parameters[0]::class === IsAnything::class) { + $message .= "\nTo allow 0 or more parameters with any value, omit ->with() or use ->withAnyParameters() instead."; + } + + $this->incrementAssertionCount(); + + throw new ExpectationFailedException( + sprintf($message, $this->invocation->toString()), + ); + } + + foreach ($this->parameters as $i => $parameter) { + if ($parameter instanceof Callback && $parameter->isVariadic()) { + $other = $this->invocation->parameters(); + } else { + $other = $this->invocation->parameters()[$i]; + } + + $this->incrementAssertionCount(); + + $parameter->evaluate( + $other, + sprintf( + 'Parameter %s for invocation %s does not match expected value.', + $i, + $this->invocation->toString(), + ), + ); + } + + return true; + } + + /** + * @throws ExpectationFailedException + */ + private function guardAgainstDuplicateEvaluationOfParameterConstraints(): bool + { + if ($this->parameterVerificationResult instanceof ExpectationFailedException) { + throw $this->parameterVerificationResult; + } + + return (bool) $this->parameterVerificationResult; + } + + private function incrementAssertionCount(): void + { + Test::currentTestCase()->addToAssertionCount(1); + } +} diff --git a/src/Framework/MockObject/Runtime/Rule/ParametersRule.php b/src/Framework/MockObject/Runtime/Rule/ParametersRule.php new file mode 100644 index 00000000000..03cfe2a48fa --- /dev/null +++ b/src/Framework/MockObject/Runtime/Rule/ParametersRule.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Rule; + +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Invocation as BaseInvocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface ParametersRule +{ + /** + * @throws ExpectationFailedException if the invocation violates the rule + */ + public function apply(BaseInvocation $invocation): void; + + public function verify(): void; +} diff --git a/src/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php b/src/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php new file mode 100644 index 00000000000..b518f1cf4b3 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ConsecutiveCalls.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function array_shift; +use function count; +use PHPUnit\Framework\MockObject\Invocation; +use PHPUnit\Framework\MockObject\NoMoreReturnValuesConfiguredException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ConsecutiveCalls implements Stub +{ + /** + * @var array + */ + private array $stack; + private int $numberOfConfiguredReturnValues; + + /** + * @param array $stack + */ + public function __construct(array $stack) + { + $this->stack = $stack; + $this->numberOfConfiguredReturnValues = count($stack); + } + + /** + * @throws NoMoreReturnValuesConfiguredException + */ + public function invoke(Invocation $invocation): mixed + { + if ($this->stack === []) { + throw new NoMoreReturnValuesConfiguredException( + $invocation, + $this->numberOfConfiguredReturnValues, + ); + } + + $value = array_shift($this->stack); + + if ($value instanceof Stub) { + $value = $value->invoke($invocation); + } + + return $value; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/Exception.php b/src/Framework/MockObject/Runtime/Stub/Exception.php new file mode 100644 index 00000000000..ce0a6804a2c --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/Exception.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Exception implements Stub +{ + private Throwable $exception; + + public function __construct(Throwable $exception) + { + $this->exception = $exception; + } + + /** + * @throws Throwable + */ + public function invoke(Invocation $invocation): never + { + throw $this->exception; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnArgument.php b/src/Framework/MockObject/Runtime/Stub/ReturnArgument.php new file mode 100644 index 00000000000..daca5099d03 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnArgument.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnArgument implements Stub +{ + private int $argumentIndex; + + public function __construct(int $argumentIndex) + { + $this->argumentIndex = $argumentIndex; + } + + public function invoke(Invocation $invocation): mixed + { + return $invocation->parameters()[$this->argumentIndex] ?? null; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnCallback.php b/src/Framework/MockObject/Runtime/Stub/ReturnCallback.php new file mode 100644 index 00000000000..4e4cd531025 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnCallback.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function call_user_func_array; +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnCallback implements Stub +{ + /** + * @var callable + */ + private $callback; + + public function __construct(callable $callback) + { + $this->callback = $callback; + } + + public function invoke(Invocation $invocation): mixed + { + return call_user_func_array($this->callback, $invocation->parameters()); + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnReference.php b/src/Framework/MockObject/Runtime/Stub/ReturnReference.php new file mode 100644 index 00000000000..448df45273d --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnReference.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnReference implements Stub +{ + private mixed $reference; + + public function __construct(mixed &$reference) + { + $this->reference = &$reference; + } + + public function invoke(Invocation $invocation): mixed + { + return $this->reference; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnSelf.php b/src/Framework/MockObject/Runtime/Stub/ReturnSelf.php new file mode 100644 index 00000000000..4101d71acd1 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnSelf.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; +use PHPUnit\Framework\MockObject\RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ReturnSelf implements Stub +{ + /** + * @throws RuntimeException + */ + public function invoke(Invocation $invocation): object + { + return $invocation->object(); + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnStub.php b/src/Framework/MockObject/Runtime/Stub/ReturnStub.php new file mode 100644 index 00000000000..a2d881c3344 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnStub.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnStub implements Stub +{ + private mixed $value; + + public function __construct(mixed $value) + { + $this->value = $value; + } + + public function invoke(Invocation $invocation): mixed + { + return $this->value; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/ReturnValueMap.php b/src/Framework/MockObject/Runtime/Stub/ReturnValueMap.php new file mode 100644 index 00000000000..c54abc35370 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/ReturnValueMap.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use function array_pop; +use function count; +use function is_array; +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReturnValueMap implements Stub +{ + /** + * @var array + */ + private array $valueMap; + + /** + * @param array $valueMap + */ + public function __construct(array $valueMap) + { + $this->valueMap = $valueMap; + } + + public function invoke(Invocation $invocation): mixed + { + $parameterCount = count($invocation->parameters()); + + foreach ($this->valueMap as $map) { + if (!is_array($map) || $parameterCount !== (count($map) - 1)) { + continue; + } + + $return = array_pop($map); + + if ($invocation->parameters() === $map) { + return $return; + } + } + + return null; + } +} diff --git a/src/Framework/MockObject/Runtime/Stub/Stub.php b/src/Framework/MockObject/Runtime/Stub/Stub.php new file mode 100644 index 00000000000..46d9e53a933 --- /dev/null +++ b/src/Framework/MockObject/Runtime/Stub/Stub.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Stub; + +use PHPUnit\Framework\MockObject\Invocation; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Stub +{ + /** + * Fakes the processing of the invocation $invocation by returning a + * specific value. + */ + public function invoke(Invocation $invocation): mixed; +} diff --git a/src/Framework/MockObject/TestDoubleBuilder.php b/src/Framework/MockObject/TestDoubleBuilder.php new file mode 100644 index 00000000000..72a829aad88 --- /dev/null +++ b/src/Framework/MockObject/TestDoubleBuilder.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function array_merge; +use PHPUnit\Framework\MockObject\Generator\Generator; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use ReflectionClass; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TestDoubleBuilder +{ + /** + * @var class-string|trait-string + */ + protected readonly string $type; + + /** + * @var list + */ + protected array $methods = []; + protected bool $emptyMethodsArray = false; + + /** + * @var array + */ + protected array $constructorArgs = []; + protected bool $originalConstructor = true; + protected bool $originalClone = true; + protected bool $returnValueGeneration = true; + + /** + * @param class-string|trait-string $type + */ + public function __construct(string $type) + { + $this->type = $type; + } + + /** + * Specifies the subset of methods to mock, requiring each to exist in the class. + * + * @param list $methods + * + * @throws CannotUseOnlyMethodsException + * @throws ReflectionException + * + * @return $this + */ + public function onlyMethods(array $methods): self + { + if ($methods === []) { + $this->emptyMethodsArray = true; + + return $this; + } + + try { + $reflector = new ReflectionClass($this->type); + + // @codeCoverageIgnoreStart + } catch (\ReflectionException $e) { + throw new ReflectionException( + $e->getMessage(), + $e->getCode(), + $e, + ); + // @codeCoverageIgnoreEnd + } + + foreach ($methods as $method) { + if (!$reflector->hasMethod($method)) { + throw new CannotUseOnlyMethodsException($this->type, $method); + } + } + + $this->methods = array_merge($this->methods, $methods); + + return $this; + } + + /** + * Specifies the arguments for the constructor. + * + * @param array $arguments + * + * @return $this + */ + public function setConstructorArgs(array $arguments): self + { + $this->constructorArgs = $arguments; + + return $this; + } + + /** + * Disables the invocation of the original constructor. + * + * @return $this + */ + public function disableOriginalConstructor(): self + { + $this->originalConstructor = false; + + return $this; + } + + /** + * Enables the invocation of the original constructor. + * + * @return $this + */ + public function enableOriginalConstructor(): self + { + $this->originalConstructor = true; + + return $this; + } + + /** + * Disables the invocation of the original clone constructor. + * + * @return $this + */ + public function disableOriginalClone(): self + { + $this->originalClone = false; + + return $this; + } + + /** + * Enables the invocation of the original clone constructor. + * + * @return $this + */ + public function enableOriginalClone(): self + { + $this->originalClone = true; + + return $this; + } + + /** + * @return $this + */ + public function enableAutoReturnValueGeneration(): self + { + $this->returnValueGeneration = true; + + return $this; + } + + /** + * @return $this + */ + public function disableAutoReturnValueGeneration(): self + { + $this->returnValueGeneration = false; + + return $this; + } + + protected function getTestDouble(?string $testDoubleClassName, bool $mockObject): MockObject|Stub + { + return (new Generator)->testDouble( + $this->type, + $mockObject, + !$this->emptyMethodsArray ? $this->methods : null, + $this->constructorArgs, + $testDoubleClassName ?? '', + $this->originalConstructor, + $this->originalClone, + $this->returnValueGeneration, + ); + } +} diff --git a/src/Framework/MockObject/TestStubBuilder.php b/src/Framework/MockObject/TestStubBuilder.php new file mode 100644 index 00000000000..4710a3cb2ed --- /dev/null +++ b/src/Framework/MockObject/TestStubBuilder.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function assert; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\MockObject\Generator\ReflectionException; +use PHPUnit\Framework\MockObject\Generator\RuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; + +/** + * @template StubbedType + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class TestStubBuilder extends TestDoubleBuilder +{ + /** + * @var ?class-string + */ + private ?string $stubClassName = null; + + /** + * Creates a test stub using a fluent interface. + * + * @throws ClassIsEnumerationException + * @throws ClassIsFinalException + * @throws DuplicateMethodException + * @throws InvalidMethodNameException + * @throws NameAlreadyInUseException + * @throws ReflectionException + * @throws RuntimeException + * @throws UnknownTypeException + * + * @return Stub&StubbedType + */ + public function getStub(): Stub + { + $object = $this->getTestDouble($this->stubClassName, false); + + assert($object instanceof $this->type); + assert($object instanceof Stub); + assert(!$object instanceof MockObject); + + return $object; + } + + /** + * Specifies the name for the mock class. + * + * @param class-string $name + * + * @return $this + */ + public function setStubClassName(string $name): self + { + $this->stubClassName = $name; + + return $this; + } +} diff --git a/src/Framework/NativeType.php b/src/Framework/NativeType.php new file mode 100644 index 00000000000..0220e8845be --- /dev/null +++ b/src/Framework/NativeType.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +enum NativeType: string +{ + case Array = 'array'; + case Bool = 'bool'; + case Callable = 'callable'; + case ClosedResource = 'resource (closed)'; + case Float = 'float'; + case Int = 'int'; + case Iterable = 'iterable'; + case Null = 'null'; + case Numeric = 'numeric'; + case Object = 'object'; + case Resource = 'resource'; + case Scalar = 'scalar'; + case String = 'string'; +} diff --git a/src/Framework/Reorderable.php b/src/Framework/Reorderable.php new file mode 100644 index 00000000000..10f6e9431e1 --- /dev/null +++ b/src/Framework/Reorderable.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Reorderable +{ + public function sortId(): string; + + /** + * @return list + */ + public function provides(): array; + + /** + * @return list + */ + public function requires(): array; +} diff --git a/src/Framework/SelfDescribing.php b/src/Framework/SelfDescribing.php new file mode 100644 index 00000000000..bdf91a4d118 --- /dev/null +++ b/src/Framework/SelfDescribing.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface SelfDescribing +{ + /** + * Returns a string representation of the object. + */ + public function toString(): string; +} diff --git a/src/Framework/Test.php b/src/Framework/Test.php new file mode 100644 index 00000000000..b3e862f7c4e --- /dev/null +++ b/src/Framework/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Countable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Test extends Countable +{ + public function run(): void; +} diff --git a/src/Framework/TestBuilder.php b/src/Framework/TestBuilder.php new file mode 100644 index 00000000000..3eb4b1a02de --- /dev/null +++ b/src/Framework/TestBuilder.php @@ -0,0 +1,280 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_merge; +use function assert; +use PHPUnit\Metadata\Api\DataProvider; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\ProvidedData; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\BackupGlobals; +use PHPUnit\Metadata\BackupStaticProperties; +use PHPUnit\Metadata\ExcludeGlobalVariableFromBackup; +use PHPUnit\Metadata\ExcludeStaticPropertyFromBackup; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\PreserveGlobalState; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use ReflectionClass; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestBuilder +{ + /** + * @param ReflectionClass $theClass + * @param non-empty-string $methodName + * @param list $groups + * + * @throws InvalidDataProviderException + */ + public function build(ReflectionClass $theClass, string $methodName, array $groups = []): Test + { + $className = $theClass->getName(); + + $data = null; + + if ($this->requirementsSatisfied($className, $methodName)) { + try { + ErrorHandler::instance()->enterTestCaseContext($className, $methodName); + + $data = (new DataProvider)->providedData($className, $methodName); + } finally { + ErrorHandler::instance()->leaveTestCaseContext(); + } + } + + if ($data !== null) { + return $this->buildDataProviderTestSuite( + $methodName, + $className, + $data, + $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName), + $this->shouldGlobalStateBePreserved($className, $methodName), + $this->backupSettings($className, $methodName), + $groups, + ); + } + + $test = new $className($methodName); + + $this->configureTestCase( + $test, + $this->shouldTestMethodBeRunInSeparateProcess($className, $methodName), + $this->shouldGlobalStateBePreserved($className, $methodName), + $this->backupSettings($className, $methodName), + ); + + return $test; + } + + /** + * @param non-empty-string $methodName + * @param class-string $className + * @param array $data + * @param array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} $backupSettings + * @param list $groups + */ + private function buildDataProviderTestSuite(string $methodName, string $className, array $data, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings, array $groups): DataProviderTestSuite + { + $dataProviderTestSuite = DataProviderTestSuite::empty( + $className . '::' . $methodName, + ); + + $groups = array_merge( + $groups, + (new Groups)->groups($className, $methodName), + ); + + foreach ($data as $_dataName => $_data) { + $_test = new $className($methodName); + + $_test->setData($_dataName, $_data->value()); + + $this->configureTestCase( + $_test, + $runTestInSeparateProcess, + $preserveGlobalState, + $backupSettings, + ); + + $dataProviderTestSuite->addTest($_test, $groups); + } + + return $dataProviderTestSuite; + } + + /** + * @param array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} $backupSettings + */ + private function configureTestCase(TestCase $test, bool $runTestInSeparateProcess, ?bool $preserveGlobalState, array $backupSettings): void + { + if ($runTestInSeparateProcess) { + $test->setRunTestInSeparateProcess(true); + } + + if ($preserveGlobalState !== null) { + $test->setPreserveGlobalState($preserveGlobalState); + } + + if ($backupSettings['backupGlobals'] !== null) { + $test->setBackupGlobals($backupSettings['backupGlobals']); + } else { + $test->setBackupGlobals(ConfigurationRegistry::get()->backupGlobals()); + } + + $test->setBackupGlobalsExcludeList($backupSettings['backupGlobalsExcludeList']); + + if ($backupSettings['backupStaticProperties'] !== null) { + $test->setBackupStaticProperties($backupSettings['backupStaticProperties']); + } else { + $test->setBackupStaticProperties(ConfigurationRegistry::get()->backupStaticProperties()); + } + + $test->setBackupStaticPropertiesExcludeList($backupSettings['backupStaticPropertiesExcludeList']); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return array{backupGlobals: ?true, backupGlobalsExcludeList: list, backupStaticProperties: ?true, backupStaticPropertiesExcludeList: array>} + */ + private function backupSettings(string $className, string $methodName): array + { + $metadataForClass = MetadataRegistry::parser()->forClass($className); + $metadataForMethod = MetadataRegistry::parser()->forMethod($className, $methodName); + $metadataForClassAndMethod = MetadataRegistry::parser()->forClassAndMethod($className, $methodName); + + $backupGlobals = null; + $backupGlobalsExcludeList = []; + + if ($metadataForMethod->isBackupGlobals()->isNotEmpty()) { + $metadata = $metadataForMethod->isBackupGlobals()->asArray()[0]; + + assert($metadata instanceof BackupGlobals); + + if ($metadata->enabled()) { + $backupGlobals = true; + } + } elseif ($metadataForClass->isBackupGlobals()->isNotEmpty()) { + $metadata = $metadataForClass->isBackupGlobals()->asArray()[0]; + + assert($metadata instanceof BackupGlobals); + + if ($metadata->enabled()) { + $backupGlobals = true; + } + } + + foreach ($metadataForClassAndMethod->isExcludeGlobalVariableFromBackup() as $metadata) { + assert($metadata instanceof ExcludeGlobalVariableFromBackup); + + $backupGlobalsExcludeList[] = $metadata->globalVariableName(); + } + + $backupStaticProperties = null; + $backupStaticPropertiesExcludeList = []; + + if ($metadataForMethod->isBackupStaticProperties()->isNotEmpty()) { + $metadata = $metadataForMethod->isBackupStaticProperties()->asArray()[0]; + + assert($metadata instanceof BackupStaticProperties); + + if ($metadata->enabled()) { + $backupStaticProperties = true; + } + } elseif ($metadataForClass->isBackupStaticProperties()->isNotEmpty()) { + $metadata = $metadataForClass->isBackupStaticProperties()->asArray()[0]; + + assert($metadata instanceof BackupStaticProperties); + + if ($metadata->enabled()) { + $backupStaticProperties = true; + } + } + + foreach ($metadataForClassAndMethod->isExcludeStaticPropertyFromBackup() as $metadata) { + assert($metadata instanceof ExcludeStaticPropertyFromBackup); + + if (!isset($backupStaticPropertiesExcludeList[$metadata->className()])) { + $backupStaticPropertiesExcludeList[$metadata->className()] = []; + } + + $backupStaticPropertiesExcludeList[$metadata->className()][] = $metadata->propertyName(); + } + + return [ + 'backupGlobals' => $backupGlobals, + 'backupGlobalsExcludeList' => $backupGlobalsExcludeList, + 'backupStaticProperties' => $backupStaticProperties, + 'backupStaticPropertiesExcludeList' => $backupStaticPropertiesExcludeList, + ]; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function shouldGlobalStateBePreserved(string $className, string $methodName): ?bool + { + $metadataForMethod = MetadataRegistry::parser()->forMethod($className, $methodName); + + if ($metadataForMethod->isPreserveGlobalState()->isNotEmpty()) { + $metadata = $metadataForMethod->isPreserveGlobalState()->asArray()[0]; + + assert($metadata instanceof PreserveGlobalState); + + return $metadata->enabled(); + } + + $metadataForClass = MetadataRegistry::parser()->forClass($className); + + if ($metadataForClass->isPreserveGlobalState()->isNotEmpty()) { + $metadata = $metadataForClass->isPreserveGlobalState()->asArray()[0]; + + assert($metadata instanceof PreserveGlobalState); + + return $metadata->enabled(); + } + + return null; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function shouldTestMethodBeRunInSeparateProcess(string $className, string $methodName): bool + { + if (MetadataRegistry::parser()->forClass($className)->isRunTestsInSeparateProcesses()->isNotEmpty()) { + return true; + } + + if (MetadataRegistry::parser()->forMethod($className, $methodName)->isRunInSeparateProcess()->isNotEmpty()) { + return true; + } + + return false; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function requirementsSatisfied(string $className, string $methodName): bool + { + return (new Requirements)->requirementsNotSatisfiedFor($className, $methodName) === []; + } +} diff --git a/src/Framework/TestCase.php b/src/Framework/TestCase.php new file mode 100644 index 00000000000..8863b722a71 --- /dev/null +++ b/src/Framework/TestCase.php @@ -0,0 +1,2562 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_any; +use function array_keys; +use function array_merge; +use function array_reverse; +use function array_values; +use function assert; +use function chdir; +use function class_exists; +use function clearstatcache; +use function count; +use function defined; +use function error_clear_last; +use function explode; +use function fclose; +use function getcwd; +use function implode; +use function in_array; +use function ini_get; +use function ini_set; +use function is_array; +use function is_callable; +use function is_int; +use function is_object; +use function is_string; +use function is_writable; +use function libxml_clear_errors; +use function method_exists; +use function ob_end_clean; +use function ob_get_clean; +use function ob_get_contents; +use function ob_get_level; +use function ob_start; +use function preg_match; +use function preg_replace; +use function putenv; +use function restore_error_handler; +use function restore_exception_handler; +use function set_error_handler; +use function set_exception_handler; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function stream_get_contents; +use function stream_get_meta_data; +use function tmpfile; +use function trim; +use AssertionError; +use DeepCopy\DeepCopy; +use PHPUnit\Event; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Constraint\Exception as ExceptionConstraint; +use PHPUnit\Framework\Constraint\ExceptionCode; +use PHPUnit\Framework\Constraint\ExceptionMessageIsOrContains; +use PHPUnit\Framework\Constraint\ExceptionMessageMatchesRegularExpression; +use PHPUnit\Framework\MockObject\Exception as MockObjectException; +use PHPUnit\Framework\MockObject\Generator\Generator as MockGenerator; +use PHPUnit\Framework\MockObject\MockBuilder; +use PHPUnit\Framework\MockObject\MockObject; +use PHPUnit\Framework\MockObject\MockObjectInternal; +use PHPUnit\Framework\MockObject\Rule\AnyInvokedCount as AnyInvokedCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastCount as InvokedAtLeastCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtLeastOnce as InvokedAtLeastOnceMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedAtMostCount as InvokedAtMostCountMatcher; +use PHPUnit\Framework\MockObject\Rule\InvokedCount; +use PHPUnit\Framework\MockObject\Rule\InvokedCount as InvokedCountMatcher; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\MockObject\Stub\Exception as ExceptionStub; +use PHPUnit\Framework\MockObject\TestStubBuilder; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\HookMethods; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\WithEnvironmentVariable; +use PHPUnit\Runner\BackedUpEnvironmentVariable; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\HookMethodCollection; +use PHPUnit\Runner\ShutdownHandler; +use PHPUnit\TestRunner\TestResult\PassedTests; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Test as TestUtil; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; +use ReflectionObject; +use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use SebastianBergmann\Comparator\Comparator; +use SebastianBergmann\Comparator\Factory as ComparatorFactory; +use SebastianBergmann\Diff\Differ; +use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder; +use SebastianBergmann\GlobalState\ExcludeList as GlobalStateExcludeList; +use SebastianBergmann\GlobalState\Restorer; +use SebastianBergmann\GlobalState\Snapshot; +use SebastianBergmann\Invoker\TimeoutException; +use SebastianBergmann\ObjectEnumerator\Enumerator; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract class TestCase extends Assert implements Reorderable, SelfDescribing, Test +{ + private ?bool $backupGlobals = null; + + /** + * @var list + */ + private array $backupGlobalsExcludeList = []; + private ?bool $backupStaticProperties = null; + + /** + * @var array> + */ + private array $backupStaticPropertiesExcludeList = []; + private ?Snapshot $snapshot = null; + + /** + * @var list + */ + private ?array $backupGlobalErrorHandlers = null; + + /** + * @var list + */ + private ?array $backupGlobalExceptionHandlers = null; + private ?bool $runTestInSeparateProcess = null; + private bool $preserveGlobalState = false; + private bool $inIsolation = false; + private ?string $expectedException = null; + private ?string $expectedExceptionMessage = null; + private ?string $expectedExceptionMessageRegExp = null; + private null|int|string $expectedExceptionCode = null; + + /** + * @var list + */ + private array $backupEnvironmentVariables = []; + + /** + * @var list + */ + private array $providedTests = []; + + /** + * @var array + */ + private array $data = []; + private int|string $dataName = ''; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @var list + */ + private array $groups = []; + + /** + * @var list + */ + private array $dependencies = []; + + /** + * @var array> + */ + private array $dependencyInput = []; + + /** + * @var list + */ + private array $mockObjects = []; + private TestStatus $status; + + /** + * @var 0|positive-int + */ + private int $numberOfAssertionsPerformed = 0; + private mixed $testResult = null; + private string $output = ''; + private ?string $outputExpectedRegex = null; + private ?string $outputExpectedString = null; + private bool $outputBufferingActive = false; + private int $outputBufferingLevel; + private bool $outputRetrievedForAssertion = false; + private bool $doesNotPerformAssertions = false; + private bool $expectErrorLog = false; + + /** + * @var list + */ + private array $customComparators = []; + private ?Event\Code\TestMethod $testValueObjectForEvents = null; + private bool $wasPrepared = false; + + /** + * @var array + */ + private array $failureTypes = []; + + /** + * @var list + */ + private array $expectedUserDeprecationMessage = []; + + /** + * @var list + */ + private array $expectedUserDeprecationMessageRegularExpression = []; + + /** + * @var false|resource + */ + private mixed $errorLogCapture = false; + private false|string $previousErrorLogTarget = false; + + /** + * @param non-empty-string $name + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function __construct(string $name) + { + $this->methodName = $name; + $this->status = TestStatus::unknown(); + + if (is_callable($this->sortId(), true)) { + $this->providedTests = [new ExecutionOrderDependency($this->sortId())]; + } + } + + /** + * This method is called before the first test of this test class is run. + * + * @codeCoverageIgnore + */ + public static function setUpBeforeClass(): void + { + } + + /** + * This method is called after the last test of this test class is run. + * + * @codeCoverageIgnore + */ + public static function tearDownAfterClass(): void + { + } + + /** + * This method is called before each test. + * + * @codeCoverageIgnore + */ + protected function setUp(): void + { + } + + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called between setUp() and test. + * + * @codeCoverageIgnore + */ + protected function assertPreConditions(): void + { + } + + /** + * Performs assertions shared by all tests of a test case. + * + * This method is called between test and tearDown(). + * + * @codeCoverageIgnore + */ + protected function assertPostConditions(): void + { + } + + /** + * This method is called after each test. + * + * @codeCoverageIgnore + */ + protected function tearDown(): void + { + } + + /** + * Returns a string representation of the test case. + * + * @throws Exception + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function toString(): string + { + $buffer = sprintf( + '%s::%s', + new ReflectionClass($this)->getName(), + $this->methodName, + ); + + return $buffer . $this->dataSetAsStringWithData(); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function count(): int + { + return 1; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function status(): TestStatus + { + return $this->status; + } + + /** + * @throws \PHPUnit\Runner\Exception + * @throws \PHPUnit\Util\Exception + * @throws \SebastianBergmann\CodeCoverage\InvalidArgumentException + * @throws \SebastianBergmann\Template\InvalidArgumentException + * @throws Exception + * @throws NoPreviousThrowableException + * @throws ProcessIsolationException + * @throws UnintentionallyCoveredCodeException + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function run(): void + { + if (!$this->handleDependencies()) { + return; + } + + if (!$this->shouldRunInSeparateProcess() || $this->requirementsNotSatisfied()) { + try { + ShutdownHandler::setMessage(sprintf('Fatal error: Premature end of PHP process when running %s.', $this->toString())); + (new TestRunner)->run($this); + } finally { + ShutdownHandler::resetMessage(); + } + + return; + } + + IsolatedTestRunnerRegistry::run( + $this, + $this->preserveGlobalState, + $this->requiresXdebug(), + ); + } + + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function groups(): array + { + return $this->groups; + } + + /** + * @param list $groups + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setGroups(array $groups): void + { + $this->groups = $groups; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function nameWithDataSet(): string + { + return $this->methodName . $this->dataSetAsString(); + } + + /** + * @return non-empty-string + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function name(): string + { + return $this->methodName; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function size(): TestSize + { + return (new Groups)->size( + static::class, + $this->methodName, + ); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @phpstan-assert-if-true non-empty-string $this->output() + */ + final public function hasUnexpectedOutput(): bool + { + if ($this->output === '') { + return false; + } + + if ($this->expectsOutput()) { + return false; + } + + return true; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function output(): string + { + if (!$this->outputBufferingActive) { + return $this->output; + } + + return (string) ob_get_contents(); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function doesNotPerformAssertions(): bool + { + return $this->doesNotPerformAssertions; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function expectsOutput(): bool + { + return $this->hasExpectationOnOutput() || $this->outputRetrievedForAssertion; + } + + /** + * @throws Throwable + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function runBare(): void + { + $emitter = Event\Facade::emitter(); + + error_clear_last(); + clearstatcache(); + + $emitter->testPreparationStarted( + $this->valueObjectForEvents(), + ); + + $this->snapshotGlobalState(); + $this->snapshotGlobalErrorExceptionHandlers(); + $this->handleEnvironmentVariables(); + $this->startOutputBuffering(); + + $hookMethods = (new HookMethods)->hookMethods(static::class); + $hasMetRequirements = false; + $this->numberOfAssertionsPerformed = 0; + $currentWorkingDirectory = getcwd(); + + try { + $this->checkRequirements(); + $hasMetRequirements = true; + + if ($this->inIsolation) { + // @codeCoverageIgnoreStart + $this->invokeBeforeClassHookMethods($hookMethods, $emitter); + // @codeCoverageIgnoreEnd + } + + if (method_exists(static::class, $this->methodName) && + MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isDoesNotPerformAssertions()->isNotEmpty()) { + $this->doesNotPerformAssertions = true; + } + + $this->invokeBeforeTestHookMethods($hookMethods, $emitter); + $this->invokePreConditionHookMethods($hookMethods, $emitter); + + $emitter->testPrepared( + $this->valueObjectForEvents(), + ); + + $this->wasPrepared = true; + $this->testResult = $this->runTest(); + + $this->verifyDeprecationExpectations(); + $this->verifyMockObjects(); + $this->invokePostConditionHookMethods($hookMethods, $emitter); + + $this->status = TestStatus::success(); + } catch (IncompleteTest $e) { + $this->status = TestStatus::incomplete($e->getMessage()); + + $emitter->testMarkedAsIncomplete( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } catch (SkippedTest $e) { + $this->status = TestStatus::skipped($e->getMessage()); + + $emitter->testSkipped( + $this->valueObjectForEvents(), + $e->getMessage(), + ); + } catch (AssertionError|AssertionFailedError $e) { + $this->handleExceptionFromInvokedCountMockObjectRule($e); + + if (!$this->wasPrepared) { + $this->wasPrepared = true; + + $emitter->testPreparationFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } + + $this->status = TestStatus::failure($e->getMessage()); + + $emitter->testFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + Event\Code\ComparisonFailureBuilder::from($e), + ); + } catch (TimeoutException $e) { + } catch (Throwable $_e) { + if ($this->isRegisteredFailure($_e)) { + $this->status = TestStatus::failure($_e->getMessage()); + + $emitter->testFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($_e), + null, + ); + } else { + $e = $this->transformException($_e); + + $this->status = TestStatus::error($e->getMessage()); + + if (!$this->wasPrepared) { + if ($e instanceof AssertionFailedError) { + $emitter->testPreparationFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } else { + $emitter->testPreparationErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } + } + + $emitter->testErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } + } + + $outputBufferingStopped = false; + + if (!isset($e) && + $this->hasExpectationOnOutput() && + $this->stopOutputBuffering()) { + $outputBufferingStopped = true; + + $this->performAssertionsOnOutput(); + } + + try { + $this->mockObjects = []; + + /** @phpstan-ignore catch.neverThrown */ + } catch (Throwable $e) { + Event\Facade::emitter()->testErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + ); + } + + // Tear down the fixture. An exception raised in tearDown() will be + // caught and passed on when no exception was raised before. + try { + if ($hasMetRequirements) { + $this->invokeAfterTestHookMethods($hookMethods, $emitter); + + if ($this->inIsolation) { + // @codeCoverageIgnoreStart + $this->invokeAfterClassHookMethods($hookMethods, $emitter); + // @codeCoverageIgnoreEnd + } + } + } catch (AssertionError|AssertionFailedError $e) { + $this->status = TestStatus::failure($e->getMessage()); + + $emitter->testFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + Event\Code\ComparisonFailureBuilder::from($e), + ); + } catch (Throwable $exceptionRaisedDuringTearDown) { + if (!isset($e) || $e instanceof SkippedWithMessageException) { + $this->status = TestStatus::error($exceptionRaisedDuringTearDown->getMessage()); + $e = $exceptionRaisedDuringTearDown; + + $emitter->testErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($exceptionRaisedDuringTearDown), + ); + } + } + + if (!isset($e) && !isset($_e)) { + $emitter->testPassed( + $this->valueObjectForEvents(), + ); + + if (!$this->usesDataProvider()) { + PassedTests::instance()->testMethodPassed( + $this->valueObjectForEvents(), + $this->testResult, + ); + } + } + + if (!$outputBufferingStopped) { + $this->stopOutputBuffering(); + } + + clearstatcache(); + + if ($currentWorkingDirectory !== false && $currentWorkingDirectory !== getcwd()) { + chdir($currentWorkingDirectory); + } + + $this->restoreEnvironmentVariables(); + $this->restoreGlobalErrorExceptionHandlers(); + $this->restoreGlobalState(); + $this->unregisterCustomComparators(); + libxml_clear_errors(); + + $this->testValueObjectForEvents = null; + + if (isset($e)) { + $this->onNotSuccessfulTest($e); + } + } + + /** + * @param list $dependencies + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setDependencies(array $dependencies): void + { + $this->dependencies = $dependencies; + } + + /** + * @param array> $dependencyInput + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function setDependencyInput(array $dependencyInput): void + { + $this->dependencyInput = $dependencyInput; + } + + /** + * @return array> + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dependencyInput(): array + { + return $this->dependencyInput; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function hasDependencyInput(): bool + { + return $this->dependencyInput !== []; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupGlobals(bool $backupGlobals): void + { + $this->backupGlobals = $backupGlobals; + } + + /** + * @param list $backupGlobalsExcludeList + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupGlobalsExcludeList(array $backupGlobalsExcludeList): void + { + $this->backupGlobalsExcludeList = $backupGlobalsExcludeList; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupStaticProperties(bool $backupStaticProperties): void + { + $this->backupStaticProperties = $backupStaticProperties; + } + + /** + * @param array> $backupStaticPropertiesExcludeList + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setBackupStaticPropertiesExcludeList(array $backupStaticPropertiesExcludeList): void + { + $this->backupStaticPropertiesExcludeList = $backupStaticPropertiesExcludeList; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setRunTestInSeparateProcess(bool $runTestInSeparateProcess): void + { + if ($this->runTestInSeparateProcess === null) { + $this->runTestInSeparateProcess = $runTestInSeparateProcess; + } + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setPreserveGlobalState(bool $preserveGlobalState): void + { + $this->preserveGlobalState = $preserveGlobalState; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function setInIsolation(bool $inIsolation): void + { + $this->inIsolation = $inIsolation; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ + final public function result(): mixed + { + return $this->testResult; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setResult(mixed $result): void + { + $this->testResult = $result; + } + + /** + * @template RealInstanceType of object + * + * @param class-string $type + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function registerMockObject(string $type, MockObject $mockObject): void + { + assert($mockObject instanceof MockObjectInternal); + + $this->mockObjects[] = [ + 'type' => $type, + 'mockObject' => $mockObject, + ]; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function addToAssertionCount(int $count): void + { + $this->numberOfAssertionsPerformed += $count; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + * + * @return 0|positive-int + */ + final public function numberOfAssertionsPerformed(): int + { + return $this->numberOfAssertionsPerformed; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function usesDataProvider(): bool + { + return $this->data !== []; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataName(): int|string + { + return $this->dataName; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataSetAsString(): string + { + if ($this->data !== []) { + if (is_int($this->dataName)) { + return sprintf(' with data set #%s', $this->dataName); + } + + return sprintf(' with data set "%s"', $this->dataName); + } + + return ''; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function dataSetAsStringWithData(): string + { + if ($this->data === []) { + return ''; + } + + return sprintf( + '%s with data (%s)', + $this->dataSetAsFilterString(), + Exporter::shortenedRecursiveExport($this->data), + ); + } + + /** + * @return array + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function providedData(): array + { + return $this->data; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function sortId(): string + { + $id = $this->methodName; + + if (!str_contains($id, '::')) { + $id = static::class . '::' . $id; + } + + if ($this->usesDataProvider()) { + $id .= $this->dataSetAsString(); + } + + return $id; + } + + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function provides(): array + { + return $this->providedTests; + } + + /** + * @return list + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function requires(): array + { + return $this->dependencies; + } + + /** + * @param array $data + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function setData(int|string $dataName, array $data): void + { + $this->dataName = $dataName; + $this->data = $data; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function valueObjectForEvents(): Event\Code\TestMethod + { + if ($this->testValueObjectForEvents !== null) { + return $this->testValueObjectForEvents; + } + + $this->testValueObjectForEvents = Event\Code\TestMethodBuilder::fromTestCase($this); + + return $this->testValueObjectForEvents; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + final public function wasPrepared(): bool + { + return $this->wasPrepared; + } + + /** + * Returns a matcher that matches when the method is executed + * zero or more times. + */ + final protected function any(): AnyInvokedCountMatcher + { + return new AnyInvokedCountMatcher; + } + + /** + * Returns a matcher that matches when the method is never executed. + */ + final protected function never(): InvokedCountMatcher + { + return new InvokedCountMatcher(0); + } + + /** + * Returns a matcher that matches when the method is executed + * at least N times. + */ + final protected function atLeast(int $requiredInvocations): InvokedAtLeastCountMatcher + { + return new InvokedAtLeastCountMatcher( + $requiredInvocations, + ); + } + + /** + * Returns a matcher that matches when the method is executed at least once. + */ + final protected function atLeastOnce(): InvokedAtLeastOnceMatcher + { + return new InvokedAtLeastOnceMatcher; + } + + /** + * Returns a matcher that matches when the method is executed exactly once. + */ + final protected function once(): InvokedCountMatcher + { + return new InvokedCountMatcher(1); + } + + /** + * Returns a matcher that matches when the method is executed + * exactly $count times. + */ + final protected function exactly(int $count): InvokedCountMatcher + { + return new InvokedCountMatcher($count); + } + + /** + * Returns a matcher that matches when the method is executed + * at most N times. + */ + final protected function atMost(int $allowedInvocations): InvokedAtMostCountMatcher + { + return new InvokedAtMostCountMatcher($allowedInvocations); + } + + final protected function throwException(Throwable $exception): ExceptionStub + { + return new ExceptionStub($exception); + } + + final protected function getActualOutputForAssertion(): string + { + $this->outputRetrievedForAssertion = true; + + return $this->output(); + } + + final protected function expectOutputRegex(string $expectedRegex): void + { + $this->outputExpectedRegex = $expectedRegex; + } + + final protected function expectOutputString(string $expectedString): void + { + $this->outputExpectedString = $expectedString; + } + + final protected function expectErrorLog(): void + { + $this->expectErrorLog = true; + } + + /** + * @param class-string $exception + */ + final protected function expectException(string $exception): void + { + $this->expectedException = $exception; + } + + final protected function expectExceptionCode(int|string $code): void + { + $this->expectedExceptionCode = $code; + } + + final protected function expectExceptionMessage(string $message): void + { + $this->expectedExceptionMessage = $message; + } + + final protected function expectExceptionMessageMatches(string $regularExpression): void + { + $this->expectedExceptionMessageRegExp = $regularExpression; + } + + /** + * Sets up an expectation for an exception to be raised by the code under test. + * Information for expected exception class, expected exception message, and + * expected exception code are retrieved from a given Exception object. + */ + final protected function expectExceptionObject(Throwable $exception): void + { + $this->expectException($exception::class); + $this->expectExceptionMessage($exception->getMessage()); + $this->expectExceptionCode($exception->getCode()); + } + + final protected function expectNotToPerformAssertions(): void + { + $this->doesNotPerformAssertions = true; + } + + /** + * @param non-empty-string $expectedUserDeprecationMessage + */ + final protected function expectUserDeprecationMessage(string $expectedUserDeprecationMessage): void + { + $this->expectedUserDeprecationMessage[] = $expectedUserDeprecationMessage; + } + + /** + * @param non-empty-string $expectedUserDeprecationMessageRegularExpression + */ + final protected function expectUserDeprecationMessageMatches(string $expectedUserDeprecationMessageRegularExpression): void + { + $this->expectedUserDeprecationMessageRegularExpression[] = $expectedUserDeprecationMessageRegularExpression; + } + + /** + * Returns a builder object to create mock objects using a fluent interface. + * + * @template RealInstanceType of object + * + * @param class-string $className + * + * @return MockBuilder + */ + final protected function getMockBuilder(string $className): MockBuilder + { + return new MockBuilder($this, $className); + } + + final protected function registerComparator(Comparator $comparator): void + { + ComparatorFactory::getInstance()->register($comparator); + + Event\Facade::emitter()->testRegisteredComparator($comparator::class); + + $this->customComparators[] = $comparator; + } + + /** + * @param class-string $classOrInterface + */ + final protected function registerFailureType(string $classOrInterface): void + { + $this->failureTypes[$classOrInterface] = true; + } + + /** + * Creates a mock object for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return MockObject&RealInstanceType + */ + final protected function createMock(string $type): MockObject + { + $mock = (new MockGenerator)->testDouble( + $type, + true, + callOriginalConstructor: false, + callOriginalClone: false, + returnValueGeneration: self::generateReturnValuesForTestDoubles(), + ); + + assert($mock instanceof $type); + assert($mock instanceof MockObject); + + $this->registerMockObject($type, $mock); + + Event\Facade::emitter()->testCreatedMockObject($type); + + return $mock; + } + + /** + * @param list $interfaces + * + * @throws MockObjectException + */ + final protected function createMockForIntersectionOfInterfaces(array $interfaces): MockObject + { + $mock = (new MockGenerator)->testDoubleForInterfaceIntersection( + $interfaces, + true, + returnValueGeneration: self::generateReturnValuesForTestDoubles(), + ); + + assert($mock instanceof MockObject); + + $this->registerMockObject(implode('|', $interfaces), $mock); + + Event\Facade::emitter()->testCreatedMockObjectForIntersectionOfInterfaces($interfaces); + + return $mock; + } + + /** + * Creates (and configures) a mock object for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * @param array $configuration + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return MockObject&RealInstanceType + */ + final protected function createConfiguredMock(string $type, array $configuration): MockObject + { + $o = $this->createMock($type); + + foreach ($configuration as $method => $return) { + $o->method($method)->willReturn($return); + } + + return $o; + } + + /** + * Creates a partial mock object for the specified interface or class. + * + * @param class-string $type + * @param list $methods + * + * @template RealInstanceType of object + * + * @throws InvalidArgumentException + * @throws MockObjectException + * + * @return MockObject&RealInstanceType + */ + final protected function createPartialMock(string $type, array $methods): MockObject + { + $mockBuilder = $this->getMockBuilder($type) + ->disableOriginalConstructor() + ->disableOriginalClone() + ->onlyMethods($methods); + + if (!self::generateReturnValuesForTestDoubles()) { + $mockBuilder->disableAutoReturnValueGeneration(); + } + + $partialMock = $mockBuilder->getMock(); + + Event\Facade::emitter()->testCreatedPartialMockObject( + $type, + ...$methods, + ); + + return $partialMock; + } + + /** + * @param non-empty-string $additionalInformation + */ + final protected function provideAdditionalInformation(string $additionalInformation): void + { + Event\Facade::emitter()->testProvidedAdditionalInformation( + $this->valueObjectForEvents(), + $additionalInformation, + ); + } + + protected function transformException(Throwable $t): Throwable + { + return $t; + } + + /** + * This method is called when a test method did not execute successfully. + * + * @throws Throwable + */ + protected function onNotSuccessfulTest(Throwable $t): never + { + throw $t; + } + + /** + * @param array $testArguments + */ + protected function invokeTestMethod(string $methodName, array $testArguments): mixed + { + /** @phpstan-ignore method.dynamicName */ + return $this->{$methodName}(...$testArguments); + } + + /** + * Returns the data set as a string compatible with the --filter CLI option. + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + private function dataSetAsFilterString(): string + { + if ($this->data !== []) { + if (is_int($this->dataName)) { + return sprintf('#%d', $this->dataName); + } + + return sprintf('@%s', $this->dataName); + } + + return ''; + } + + /** + * @throws AssertionFailedError + * @throws Exception + * @throws ExpectationFailedException + * @throws Throwable + */ + private function runTest(): mixed + { + $testArguments = array_merge($this->data, array_values($this->dependencyInput)); + + $this->startErrorLogCapture(); + + try { + $testResult = $this->invokeTestMethod($this->methodName, $testArguments); + + $this->verifyErrorLogExpectation(); + } catch (Throwable $exception) { + $this->handleErrorLogError(); + + if (!$this->shouldExceptionExpectationsBeVerified($exception)) { + throw $exception; + } + + $this->verifyExceptionExpectations($exception); + + return null; + } finally { + $this->stopErrorLogCapture(); + } + + $this->emitEventForCustomTestMethodInvocation(); + $this->expectedExceptionWasNotRaised(); + + return $testResult; + } + + private function stripDateFromErrorLog(string $log): string + { + // https://github.com/php/php-src/blob/c696087e323263e941774ebbf902ac249774ec9f/main/main.c#L905 + return preg_replace('/\[\d+-\w+-\d+ \d+:\d+:\d+ [^\r\n[\]]+?\] /', '', $log); + } + + /** + * @throws ExpectationFailedException + */ + private function verifyDeprecationExpectations(): void + { + foreach ($this->expectedUserDeprecationMessage as $deprecationExpectation) { + $this->numberOfAssertionsPerformed++; + + if (!in_array($deprecationExpectation, DeprecationCollector::deprecations(), true)) { + throw new ExpectationFailedException( + sprintf( + 'Expected deprecation with message "%s" was not triggered', + $deprecationExpectation, + ), + ); + } + } + + foreach ($this->expectedUserDeprecationMessageRegularExpression as $deprecationExpectation) { + $this->numberOfAssertionsPerformed++; + + $expectedDeprecationTriggered = array_any( + DeprecationCollector::deprecations(), + static fn (string $deprecation) => @preg_match($deprecationExpectation, $deprecation) > 0, + ); + + if (!$expectedDeprecationTriggered) { + throw new ExpectationFailedException( + sprintf( + 'Expected deprecation with message matching regular expression "%s" was not triggered', + $deprecationExpectation, + ), + ); + } + } + } + + /** + * @throws Throwable + */ + private function verifyMockObjects(): void + { + $allowsMockObjectsWithoutExpectations = $this->allowsMockObjectsWithoutExpectations(); + $isPhpunitTestSuite = str_starts_with($this::class, 'PHPUnit\\'); + + foreach ($this->mockObjects as $mockObject) { + if (!$mockObject['mockObject']->__phpunit_hasMatchers()) { + if (!$allowsMockObjectsWithoutExpectations && !$isPhpunitTestSuite) { + Event\Facade::emitter()->testTriggeredPhpunitNotice( + $this->testValueObjectForEvents, + sprintf( + 'No expectations were configured for the mock object for %s. ' . + 'Consider refactoring your test code to use a test stub instead. ' . + 'The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check.', + $mockObject['type'], + ), + ); + } + + continue; + } + + $this->numberOfAssertionsPerformed++; + + $mockObject['mockObject']->__phpunit_verify( + $this->shouldInvocationMockerBeReset($mockObject['mockObject']), + ); + } + } + + /** + * @throws SkippedTest + */ + private function checkRequirements(): void + { + if ($this->methodName === '' || !method_exists($this, $this->methodName)) { + return; + } + + $missingRequirements = (new Requirements)->requirementsNotSatisfiedFor( + static::class, + $this->methodName, + ); + + if ($missingRequirements !== []) { + $this->markTestSkipped(implode(PHP_EOL, $missingRequirements)); + } + } + + private function handleDependencies(): bool + { + if ([] === $this->dependencies || $this->inIsolation) { + return true; + } + + $passedTests = PassedTests::instance(); + + foreach ($this->dependencies as $dependency) { + if (!$dependency->isValid()) { + $this->markErrorForInvalidDependency(); + + return false; + } + + if ($dependency->targetIsClass()) { + $dependencyClassName = $dependency->getTargetClassName(); + + if (!class_exists($dependencyClassName)) { + $this->markErrorForInvalidDependency($dependency); + + return false; + } + + if (!$passedTests->hasTestClassPassed($dependencyClassName)) { + $this->markSkippedForMissingDependency($dependency); + + return false; + } + + continue; + } + + $dependencyTarget = $dependency->getTarget(); + + if (!$passedTests->hasTestMethodPassed($dependencyTarget)) { + if (!$this->isCallableTestMethod($dependencyTarget)) { + $this->markErrorForInvalidDependency($dependency); + } else { + $this->markSkippedForMissingDependency($dependency); + } + + return false; + } + + if ($passedTests->isGreaterThan($dependencyTarget, $this->size())) { + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + 'This test depends on a test that is larger than itself', + ); + + return true; + } + + if (!$passedTests->hasReturnValue($dependencyTarget)) { + return true; + } + + $returnValue = $passedTests->returnValue($dependencyTarget); + + if ($dependency->deepClone()) { + $deepCopy = new DeepCopy; + $deepCopy->skipUncloneable(false); + + $this->dependencyInput[$dependencyTarget] = $deepCopy->copy($returnValue); + } elseif ($dependency->shallowClone()) { + $this->dependencyInput[$dependencyTarget] = clone $returnValue; + } else { + $this->dependencyInput[$dependencyTarget] = $returnValue; + } + } + + $this->testValueObjectForEvents = null; + + return true; + } + + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + private function markErrorForInvalidDependency(?ExecutionOrderDependency $dependency = null): void + { + $message = 'This test has an invalid dependency'; + + if ($dependency !== null) { + $message = sprintf( + 'This test depends on "%s" which does not exist', + $dependency->targetIsClass() ? $dependency->getTargetClassName() : $dependency->getTarget(), + ); + } + + $exception = new InvalidDependencyException($message); + + Event\Facade::emitter()->testErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($exception), + ); + + $this->status = TestStatus::error($message); + } + + private function markSkippedForMissingDependency(ExecutionOrderDependency $dependency): void + { + $message = sprintf( + 'This test depends on "%s" to pass', + $dependency->getTarget(), + ); + + Event\Facade::emitter()->testSkipped( + $this->valueObjectForEvents(), + $message, + ); + + $this->status = TestStatus::skipped($message); + } + + private function startOutputBuffering(): void + { + ob_start(); + + $this->outputBufferingActive = true; + $this->outputBufferingLevel = ob_get_level(); + } + + private function stopOutputBuffering(): bool + { + $bufferingLevel = ob_get_level(); + + if ($bufferingLevel !== $this->outputBufferingLevel) { + if ($bufferingLevel > $this->outputBufferingLevel) { + $message = 'Test code or tested code did not close its own output buffers'; + } else { + $message = 'Test code or tested code closed output buffers other than its own'; + } + + while (ob_get_level() >= $this->outputBufferingLevel) { + ob_end_clean(); + } + + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + $message, + ); + + return false; + } + + $this->output = ob_get_clean(); + + $this->outputBufferingActive = false; + $this->outputBufferingLevel = ob_get_level(); + + return true; + } + + private function snapshotGlobalErrorExceptionHandlers(): void + { + $this->backupGlobalErrorHandlers = $this->activeErrorHandlers(); + $this->backupGlobalExceptionHandlers = $this->activeExceptionHandlers(); + } + + private function restoreGlobalErrorExceptionHandlers(): void + { + $activeErrorHandlers = $this->activeErrorHandlers(); + $activeExceptionHandlers = $this->activeExceptionHandlers(); + + $message = null; + + if ($activeErrorHandlers !== $this->backupGlobalErrorHandlers) { + if (count($activeErrorHandlers) > count($this->backupGlobalErrorHandlers)) { + if (!$this->inIsolation) { + $message = 'Test code or tested code did not remove its own error handlers'; + } + } else { + $message = 'Test code or tested code removed error handlers other than its own'; + } + + foreach ($activeErrorHandlers as $handler) { + restore_error_handler(); + } + + foreach ($this->backupGlobalErrorHandlers as $handler) { + set_error_handler($handler); + } + } + + if ($message !== null) { + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + $message, + ); + } + + $message = null; + + if ($activeExceptionHandlers !== $this->backupGlobalExceptionHandlers) { + if (count($activeExceptionHandlers) > count($this->backupGlobalExceptionHandlers)) { + if (!$this->inIsolation) { + $message = 'Test code or tested code did not remove its own exception handlers'; + } + } else { + $message = 'Test code or tested code removed exception handlers other than its own'; + } + + foreach ($activeExceptionHandlers as $handler) { + restore_exception_handler(); + } + + foreach ($this->backupGlobalExceptionHandlers as $handler) { + set_exception_handler($handler); + } + } + + $this->backupGlobalErrorHandlers = null; + $this->backupGlobalExceptionHandlers = null; + + if ($message !== null) { + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + $message, + ); + } + } + + /** + * @return list + */ + private function activeErrorHandlers(): array + { + $activeErrorHandlers = []; + + while (true) { + $previousHandler = set_error_handler(static fn () => false); + + restore_error_handler(); + + if ($previousHandler === null) { + break; + } + + $activeErrorHandlers[] = $previousHandler; + + restore_error_handler(); + } + + $activeErrorHandlers = array_reverse($activeErrorHandlers); + $invalidErrorHandlerStack = false; + + foreach ($activeErrorHandlers as $handler) { + if (!is_callable($handler)) { + $invalidErrorHandlerStack = true; + + continue; + } + + set_error_handler($handler); + } + + if ($invalidErrorHandlerStack) { + $message = 'At least one error handler is not callable outside the scope it was registered in'; + + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + $message, + ); + } + + return $activeErrorHandlers; + } + + /** + * @return list + */ + private function activeExceptionHandlers(): array + { + $res = []; + + while (true) { + $previousHandler = set_exception_handler(static fn () => null); + restore_exception_handler(); + + if ($previousHandler === null) { + break; + } + $res[] = $previousHandler; + restore_exception_handler(); + } + $res = array_reverse($res); + + foreach ($res as $handler) { + set_exception_handler($handler); + } + + return $res; + } + + private function snapshotGlobalState(): void + { + if ($this->runTestInSeparateProcess || $this->inIsolation || + (!$this->backupGlobals && !$this->backupStaticProperties)) { + return; + } + + $snapshot = $this->createGlobalStateSnapshot($this->backupGlobals === true); + + $this->snapshot = $snapshot; + } + + private function restoreGlobalState(): void + { + if (!$this->snapshot instanceof Snapshot) { + return; + } + + if (ConfigurationRegistry::get()->beStrictAboutChangesToGlobalState()) { + $this->compareGlobalStateSnapshots( + $this->snapshot, + $this->createGlobalStateSnapshot($this->backupGlobals === true), + ); + } + + $restorer = new Restorer; + + if ($this->backupGlobals) { + $restorer->restoreGlobalVariables($this->snapshot); + } + + if ($this->backupStaticProperties) { + $restorer->restoreStaticProperties($this->snapshot); + } + + $this->snapshot = null; + } + + private function createGlobalStateSnapshot(bool $backupGlobals): Snapshot + { + $excludeList = new GlobalStateExcludeList; + + foreach ($this->backupGlobalsExcludeList as $globalVariable) { + $excludeList->addGlobalVariable($globalVariable); + } + + if (!defined('PHPUNIT_TESTSUITE')) { + $excludeList->addClassNamePrefix('PHPUnit'); + $excludeList->addClassNamePrefix('SebastianBergmann\CodeCoverage'); + $excludeList->addClassNamePrefix('SebastianBergmann\FileIterator'); + $excludeList->addClassNamePrefix('SebastianBergmann\Invoker'); + $excludeList->addClassNamePrefix('SebastianBergmann\Template'); + $excludeList->addClassNamePrefix('SebastianBergmann\Timer'); + $excludeList->addStaticProperty(ComparatorFactory::class, 'instance'); + + foreach ($this->backupStaticPropertiesExcludeList as $class => $properties) { + foreach ($properties as $property) { + $excludeList->addStaticProperty($class, $property); + } + } + } + + try { + return new Snapshot( + $excludeList, + $backupGlobals, + (bool) $this->backupStaticProperties, + false, + false, + false, + false, + false, + false, + false, + ); + } catch (Throwable $t) { + Event\Facade::emitter()->testPreparationFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($t), + ); + + Event\Facade::emitter()->testErrored( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($t), + ); + + throw $t; + } + } + + private function compareGlobalStateSnapshots(Snapshot $before, Snapshot $after): void + { + $backupGlobals = $this->backupGlobals === null || $this->backupGlobals; + + if ($backupGlobals) { + $this->compareGlobalStateSnapshotPart( + $before->globalVariables(), + $after->globalVariables(), + "--- Global variables before the test\n+++ Global variables after the test\n", + ); + + $this->compareGlobalStateSnapshotPart( + $before->superGlobalVariables(), + $after->superGlobalVariables(), + "--- Super-global variables before the test\n+++ Super-global variables after the test\n", + ); + } + + if ($this->backupStaticProperties) { + $this->compareGlobalStateSnapshotPart( + $before->staticProperties(), + $after->staticProperties(), + "--- Static properties before the test\n+++ Static properties after the test\n", + ); + } + } + + /** + * @param array $before + * @param array $after + */ + private function compareGlobalStateSnapshotPart(array $before, array $after, string $header): void + { + if ($before === $after) { + return; + } + + $differ = new Differ(new UnifiedDiffOutputBuilder($header)); + + Event\Facade::emitter()->testConsideredRisky( + $this->valueObjectForEvents(), + 'This test modified global state but was not expected to do so' . PHP_EOL . + trim( + $differ->diff( + Exporter::export($before), + Exporter::export($after), + ), + ), + ); + } + + private function handleEnvironmentVariables(): void + { + $withEnvironmentVariables = MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isWithEnvironmentVariable(); + + $environmentVariables = []; + + foreach ($withEnvironmentVariables as $metadata) { + assert($metadata instanceof WithEnvironmentVariable); + + $environmentVariables[$metadata->environmentVariableName()] = $metadata->value(); + } + + foreach ($environmentVariables as $environmentVariableName => $environmentVariableValue) { + $this->backupEnvironmentVariables = [...$this->backupEnvironmentVariables, ...BackedUpEnvironmentVariable::create($environmentVariableName)]; + + if ($environmentVariableValue === null) { + unset($_ENV[$environmentVariableName]); + putenv($environmentVariableName); + } else { + $_ENV[$environmentVariableName] = $environmentVariableValue; + putenv("{$environmentVariableName}={$environmentVariableValue}"); + } + } + } + + private function restoreEnvironmentVariables(): void + { + foreach ($this->backupEnvironmentVariables as $backupEnvironmentVariable) { + $backupEnvironmentVariable->restore(); + } + + $this->backupEnvironmentVariables = []; + } + + private function shouldInvocationMockerBeReset(MockObject $mock): bool + { + $enumerator = new Enumerator; + + if (in_array($mock, $enumerator->enumerate($this->dependencyInput), true)) { + return false; + } + + if (!is_array($this->testResult) && !is_object($this->testResult)) { + return true; + } + + return !in_array($mock, $enumerator->enumerate($this->testResult), true); + } + + private function unregisterCustomComparators(): void + { + $factory = ComparatorFactory::getInstance(); + + foreach ($this->customComparators as $comparator) { + $factory->unregister($comparator); + } + + $this->customComparators = []; + } + + /** + * @throws Exception + */ + private function shouldExceptionExpectationsBeVerified(Throwable $throwable): bool + { + $result = false; + + if ($this->expectedException !== null || $this->expectedExceptionCode !== null || $this->expectedExceptionMessage !== null || $this->expectedExceptionMessageRegExp !== null) { + $result = true; + } + + if ($throwable instanceof Exception) { + $result = false; + } + + if (is_string($this->expectedException)) { + try { + $reflector = new ReflectionClass($this->expectedException); + // @codeCoverageIgnoreStart + } catch (ReflectionException $e) { + throw new Exception( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + // @codeCoverageIgnoreEnd + + if ($this->expectedException === 'PHPUnit\Framework\Exception' || + $this->expectedException === '\PHPUnit\Framework\Exception' || + $reflector->isSubclassOf(Exception::class)) { + $result = true; + } + } + + return $result; + } + + private function shouldRunInSeparateProcess(): bool + { + if ($this->inIsolation) { + return false; + } + + if ($this->runTestInSeparateProcess) { + return true; + } + + return ConfigurationRegistry::get()->processIsolation(); + } + + private function isCallableTestMethod(string $dependency): bool + { + [$className, $methodName] = explode('::', $dependency); + + if (!class_exists($className)) { + return false; + } + + $class = new ReflectionClass($className); + + if (!$class->isSubclassOf(__CLASS__)) { + return false; + } + + if (!$class->hasMethod($methodName)) { + return false; + } + + return TestUtil::isTestMethod( + $class->getMethod($methodName), + ); + } + + /** + * @throws Exception + * @throws ExpectationFailedException + * @throws NoPreviousThrowableException + */ + private function performAssertionsOnOutput(): void + { + try { + if ($this->outputExpectedRegex !== null) { + $this->assertMatchesRegularExpression($this->outputExpectedRegex, $this->output); + } elseif ($this->outputExpectedString !== null) { + $this->assertSame($this->outputExpectedString, $this->output); + } + } catch (ExpectationFailedException $e) { + $this->status = TestStatus::failure($e->getMessage()); + + Event\Facade::emitter()->testFailed( + $this->valueObjectForEvents(), + Event\Code\ThrowableBuilder::from($e), + Event\Code\ComparisonFailureBuilder::from($e), + ); + + throw $e; + } + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + * + * @codeCoverageIgnore + */ + private function invokeBeforeClassHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['beforeClass'], + $emitter, + 'beforeFirstTestMethodCalled', + 'beforeFirstTestMethodErrored', + 'beforeFirstTestMethodFailed', + 'beforeFirstTestMethodFinished', + false, + ); + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokeBeforeTestHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['before'], + $emitter, + 'beforeTestMethodCalled', + 'beforeTestMethodErrored', + 'beforeTestMethodFailed', + 'beforeTestMethodFinished', + ); + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokePreConditionHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['preCondition'], + $emitter, + 'preConditionCalled', + 'preConditionErrored', + 'preConditionFailed', + 'preConditionFinished', + ); + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokePostConditionHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['postCondition'], + $emitter, + 'postConditionCalled', + 'postConditionErrored', + 'postConditionFailed', + 'postConditionFinished', + ); + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + */ + private function invokeAfterTestHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['after'], + $emitter, + 'afterTestMethodCalled', + 'afterTestMethodErrored', + 'afterTestMethodFailed', + 'afterTestMethodFinished', + ); + } + + /** + * @param array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} $hookMethods + * + * @throws Throwable + * + * @codeCoverageIgnore + */ + private function invokeAfterClassHookMethods(array $hookMethods, Event\Emitter $emitter): void + { + $this->invokeHookMethods( + $hookMethods['afterClass'], + $emitter, + 'afterLastTestMethodCalled', + 'afterLastTestMethodErrored', + 'afterLastTestMethodFailed', + 'afterLastTestMethodFinished', + false, + ); + } + + /** + * @param 'afterLastTestMethodCalled'|'afterTestMethodCalled'|'beforeFirstTestMethodCalled'|'beforeTestMethodCalled'|'postConditionCalled'|'preConditionCalled' $calledMethod + * @param 'afterLastTestMethodErrored'|'afterTestMethodErrored'|'beforeFirstTestMethodErrored'|'beforeTestMethodErrored'|'postConditionErrored'|'preConditionErrored' $erroredMethod + * @param 'afterLastTestMethodFailed'|'afterTestMethodFailed'|'beforeFirstTestMethodFailed'|'beforeTestMethodFailed'|'postConditionFailed'|'preConditionFailed' $failedMethod + * @param 'afterLastTestMethodFinished'|'afterTestMethodFinished'|'beforeFirstTestMethodFinished'|'beforeTestMethodFinished'|'postConditionFinished'|'preConditionFinished' $finishedMethod + * + * @throws Throwable + */ + private function invokeHookMethods(HookMethodCollection $hookMethods, Event\Emitter $emitter, string $calledMethod, string $erroredMethod, string $failedMethod, string $finishedMethod, bool $forTestCase = true): void + { + if ($forTestCase) { + $test = $this->valueObjectForEvents(); + } else { + $test = static::class; + } + + $methodsInvoked = []; + + foreach ($hookMethods->methodNamesSortedByPriority() as $methodName) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($methodName)) { + continue; + } + + $methodInvoked = new Event\Code\ClassMethod( + static::class, + $methodName, + ); + + try { + /** @phpstan-ignore method.dynamicName */ + $this->{$methodName}(); + } catch (Throwable $t) { + } + + /** @phpstan-ignore method.dynamicName */ + $emitter->{$calledMethod}( + $test, + $methodInvoked + ); + + $methodsInvoked[] = $methodInvoked; + + if (isset($t) && !$t instanceof SkippedTest) { + if ($t instanceof AssertionFailedError) { + $method = $failedMethod; + } else { + $method = $erroredMethod; + } + + /** @phpstan-ignore method.dynamicName */ + $emitter->{$method}( + $test, + $methodInvoked, + Event\Code\ThrowableBuilder::from($t), + ); + + break; + } + } + + if ($methodsInvoked !== []) { + /** @phpstan-ignore method.dynamicName */ + $emitter->{$finishedMethod}( + $test, + ...$methodsInvoked + ); + } + + if (isset($t)) { + throw $t; + } + } + + /** + * @param non-empty-string $methodName + */ + private function methodDoesNotExistOrIsDeclaredInTestCase(string $methodName): bool + { + $reflector = new ReflectionObject($this); + + return !$reflector->hasMethod($methodName) || + $reflector->getMethod($methodName)->getDeclaringClass()->getName() === self::class; + } + + /** + * @throws ExpectationFailedException + */ + private function verifyExceptionExpectations(\Exception|Throwable $exception): void + { + if ($this->expectedException !== null) { + $this->assertThat( + $exception, + new ExceptionConstraint( + $this->expectedException, + ), + ); + } + + if ($this->expectedExceptionMessage !== null) { + $this->assertThat( + $exception->getMessage(), + new ExceptionMessageIsOrContains( + $this->expectedExceptionMessage, + ), + ); + } + + if ($this->expectedExceptionMessageRegExp !== null) { + $this->assertThat( + $exception->getMessage(), + new ExceptionMessageMatchesRegularExpression( + $this->expectedExceptionMessageRegExp, + ), + ); + } + + if ($this->expectedExceptionCode !== null) { + $this->assertThat( + $exception->getCode(), + new ExceptionCode( + $this->expectedExceptionCode, + ), + ); + } + } + + /** + * @throws AssertionFailedError + */ + private function expectedExceptionWasNotRaised(): void + { + if ($this->expectedException !== null) { + $this->assertThat( + null, + new ExceptionConstraint($this->expectedException), + ); + } elseif ($this->expectedExceptionMessage !== null) { + $this->numberOfAssertionsPerformed++; + + throw new AssertionFailedError( + sprintf( + 'Failed asserting that exception with message "%s" is thrown', + $this->expectedExceptionMessage, + ), + ); + } elseif ($this->expectedExceptionMessageRegExp !== null) { + $this->numberOfAssertionsPerformed++; + + throw new AssertionFailedError( + sprintf( + 'Failed asserting that exception with message matching "%s" is thrown', + $this->expectedExceptionMessageRegExp, + ), + ); + } elseif ($this->expectedExceptionCode !== null) { + $this->numberOfAssertionsPerformed++; + + throw new AssertionFailedError( + sprintf( + 'Failed asserting that exception with code "%s" is thrown', + $this->expectedExceptionCode, + ), + ); + } + } + + private function isRegisteredFailure(Throwable $t): bool + { + return array_any( + array_keys($this->failureTypes), + static fn (string $failureType) => $t instanceof $failureType, + ); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + private function hasExpectationOnOutput(): bool + { + return is_string($this->outputExpectedString) || is_string($this->outputExpectedRegex); + } + + private function requirementsNotSatisfied(): bool + { + return (new Requirements)->requirementsNotSatisfiedFor(static::class, $this->methodName) !== []; + } + + private function requiresXdebug(): bool + { + return (new Requirements)->requiresXdebug(static::class, $this->methodName); + } + + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/6095 + */ + private function handleExceptionFromInvokedCountMockObjectRule(Throwable $t): void + { + if (!$t instanceof ExpectationFailedException) { + return; + } + + $trace = $t->getTrace(); + + if (isset($trace[0]['class']) && $trace[0]['class'] === InvokedCount::class) { + $this->numberOfAssertionsPerformed++; + } + } + + private function startErrorLogCapture(): void + { + if (ini_get('display_errors') === '0') { + ShutdownHandler::setMessage( + 'Fatal error: Premature end of PHPUnit\'s PHP process. Use display_errors=On to see the error message.', + ); + } + + $errorLogCapture = tmpfile(); + + if ($errorLogCapture === false) { + return; + } + + $capturePath = stream_get_meta_data($errorLogCapture)['uri']; + + if (!@is_writable($capturePath)) { + return; + } + + $this->errorLogCapture = $errorLogCapture; + $this->previousErrorLogTarget = ini_set('error_log', $capturePath); + } + + /** + * @throws ErrorLogNotWritableException + */ + private function verifyErrorLogExpectation(): void + { + if ($this->errorLogCapture === false) { + if ($this->expectErrorLog) { + throw new ErrorLogNotWritableException; + } + + return; + } + + $errorLogOutput = stream_get_contents($this->errorLogCapture); + + if ($this->expectErrorLog) { + $this->assertNotEmpty($errorLogOutput, 'error_log() was not called'); + + return; + } + + if ($errorLogOutput === false) { + return; + } + + print $this->stripDateFromErrorLog($errorLogOutput); + } + + private function handleErrorLogError(): void + { + if ($this->errorLogCapture === false) { + return; + } + + if ($this->expectErrorLog) { + return; + } + + $errorLogOutput = stream_get_contents($this->errorLogCapture); + + if ($errorLogOutput !== false) { + print $this->stripDateFromErrorLog($errorLogOutput); + } + } + + private function stopErrorLogCapture(): void + { + if ($this->errorLogCapture === false) { + return; + } + + ShutdownHandler::resetMessage(); + + fclose($this->errorLogCapture); + + $this->errorLogCapture = false; + + if ($this->previousErrorLogTarget === false) { + return; + } + + ini_set('error_log', $this->previousErrorLogTarget); + + $this->previousErrorLogTarget = false; + } + + private function allowsMockObjectsWithoutExpectations(): bool + { + return MetadataRegistry::parser()->forClassAndMethod(static::class, $this->methodName)->isAllowMockObjectsWithoutExpectations()->isNotEmpty(); + } + + private function emitEventForCustomTestMethodInvocation(): void + { + $reflector = new ReflectionMethod($this, 'invokeTestMethod'); + + if (self::class === $reflector->getDeclaringClass()->getName()) { + return; + } + + Event\Facade::emitter()->testUsedCustomMethodInvocation( + $this->valueObjectForEvents(), + new Event\Code\ClassMethod( + $reflector->getDeclaringClass()->getName(), + 'invokeTestMethod', + ), + ); + } + + /** + * Returns a builder object to create test stubs using a fluent interface. + * + * @template RealInstanceType of object + * + * @param class-string $className + * + * @return TestStubBuilder + */ + final protected static function getStubBuilder(string $className): TestStubBuilder + { + return new TestStubBuilder($className); + } + + /** + * Creates a test stub for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return RealInstanceType&Stub + */ + final protected static function createStub(string $type): Stub + { + $stub = (new MockGenerator)->testDouble( + $type, + false, + callOriginalConstructor: false, + callOriginalClone: false, + returnValueGeneration: self::generateReturnValuesForTestDoubles(), + ); + + Event\Facade::emitter()->testCreatedStub($type); + + assert($stub instanceof $type); + assert($stub instanceof Stub); + + return $stub; + } + + /** + * @param list $interfaces + * + * @throws MockObjectException + */ + final protected static function createStubForIntersectionOfInterfaces(array $interfaces): Stub + { + $stub = (new MockGenerator)->testDoubleForInterfaceIntersection( + $interfaces, + false, + returnValueGeneration: self::generateReturnValuesForTestDoubles(), + ); + + Event\Facade::emitter()->testCreatedStubForIntersectionOfInterfaces($interfaces); + + return $stub; + } + + /** + * Creates (and configures) a test stub for the specified interface or class. + * + * @template RealInstanceType of object + * + * @param class-string $type + * @param array $configuration + * + * @throws InvalidArgumentException + * @throws MockObjectException + * @throws NoPreviousThrowableException + * + * @return RealInstanceType&Stub + */ + final protected static function createConfiguredStub(string $type, array $configuration): Stub + { + $o = self::createStub($type); + + foreach ($configuration as $method => $return) { + $o->method($method)->willReturn($return); + } + + return $o; + } + + private static function generateReturnValuesForTestDoubles(): bool + { + return MetadataRegistry::parser()->forClass(static::class)->isDisableReturnValueGenerationForTestDoubles()->isEmpty(); + } +} diff --git a/src/Framework/TestRunner/ChildProcessResultProcessor.php b/src/Framework/TestRunner/ChildProcessResultProcessor.php new file mode 100644 index 00000000000..af487c1964e --- /dev/null +++ b/src/Framework/TestRunner/ChildProcessResultProcessor.php @@ -0,0 +1,99 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function trim; +use function unserialize; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Emitter; +use PHPUnit\Event\Facade; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestRunner\TestResult\PassedTests; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessResultProcessor +{ + private Facade $eventFacade; + private Emitter $emitter; + private PassedTests $passedTests; + private CodeCoverage $codeCoverage; + + public function __construct(Facade $eventFacade, Emitter $emitter, PassedTests $passedTests, CodeCoverage $codeCoverage) + { + $this->eventFacade = $eventFacade; + $this->emitter = $emitter; + $this->passedTests = $passedTests; + $this->codeCoverage = $codeCoverage; + } + + public function process(Test $test, string $serializedProcessResult, string $stderr): void + { + if ($stderr !== '') { + $exception = new Exception(trim($stderr)); + + assert($test instanceof TestCase); + + $this->emitter->testErrored( + TestMethodBuilder::fromTestCase($test), + ThrowableBuilder::from($exception), + ); + + return; + } + + $childResult = @unserialize($serializedProcessResult); + + if ($childResult === false) { + $this->emitter->childProcessErrored(); + + $exception = new AssertionFailedError('Test was run in child process and ended unexpectedly'); + + assert($test instanceof TestCase); + + $this->emitter->testErrored( + TestMethodBuilder::fromTestCase($test), + ThrowableBuilder::from($exception), + ); + + $this->emitter->testFinished( + TestMethodBuilder::fromTestCase($test), + 0, + ); + + return; + } + + $this->eventFacade->forward($childResult->events); + $this->passedTests->import($childResult->passedTests); + + assert($test instanceof TestCase); + + $test->setResult($childResult->testResult); + $test->addToAssertionCount($childResult->numAssertions); + + if (!$this->codeCoverage->isActive()) { + return; + } + + // @codeCoverageIgnoreStart + if (!$childResult->codeCoverage instanceof \SebastianBergmann\CodeCoverage\CodeCoverage) { + return; + } + + CodeCoverage::instance()->codeCoverage()->merge( + $childResult->codeCoverage, + ); + // @codeCoverageIgnoreEnd + } +} diff --git a/src/Framework/TestRunner/IsolatedTestRunner.php b/src/Framework/TestRunner/IsolatedTestRunner.php new file mode 100644 index 00000000000..82ac6460757 --- /dev/null +++ b/src/Framework/TestRunner/IsolatedTestRunner.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface IsolatedTestRunner +{ + public function run(TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void; +} diff --git a/src/Framework/TestRunner/IsolatedTestRunnerRegistry.php b/src/Framework/TestRunner/IsolatedTestRunnerRegistry.php new file mode 100644 index 00000000000..68cf84c9c42 --- /dev/null +++ b/src/Framework/TestRunner/IsolatedTestRunnerRegistry.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IsolatedTestRunnerRegistry +{ + private static ?IsolatedTestRunner $runner = null; + + public static function run(TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void + { + if (self::$runner === null) { + self::$runner = new SeparateProcessTestRunner; + } + + self::$runner->run($test, $preserveGlobalState, $requiresXdebug); + } + + public static function set(IsolatedTestRunner $runner): void + { + self::$runner = $runner; + } +} diff --git a/src/Framework/TestRunner/SeparateProcessTestRunner.php b/src/Framework/TestRunner/SeparateProcessTestRunner.php new file mode 100644 index 00000000000..f838684fad5 --- /dev/null +++ b/src/Framework/TestRunner/SeparateProcessTestRunner.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function defined; +use function get_include_path; +use function hrtime; +use function serialize; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use function var_export; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use PHPUnit\Util\GlobalState; +use PHPUnit\Util\PHP\Job; +use PHPUnit\Util\PHP\JobRunnerRegistry; +use ReflectionClass; +use SebastianBergmann\Template\InvalidArgumentException; +use SebastianBergmann\Template\Template; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SeparateProcessTestRunner implements IsolatedTestRunner +{ + /** + * @throws \PHPUnit\Runner\Exception + * @throws \PHPUnit\Util\Exception + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws ProcessIsolationException + */ + public function run(TestCase $test, bool $preserveGlobalState, bool $requiresXdebug): void + { + $class = new ReflectionClass($test); + + $bootstrap = ''; + $constants = ''; + $globals = ''; + $includedFiles = ''; + $iniSettings = ''; + + if (ConfigurationRegistry::get()->hasBootstrap()) { + $bootstrap = ConfigurationRegistry::get()->bootstrap(); + } + + if ($preserveGlobalState) { + $constants = GlobalState::getConstantsAsString(); + $globals = GlobalState::getGlobalsAsString(); + $includedFiles = GlobalState::getIncludedFilesAsString(); + $iniSettings = GlobalState::getIniSettingsAsString(); + } + + $coverage = CodeCoverage::instance()->isActive() ? 'true' : 'false'; + + if (defined('PHPUNIT_COMPOSER_INSTALL')) { + $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true); + } else { + $composerAutoload = '\'\''; + } + + if (defined('__PHPUNIT_PHAR__')) { + $phar = var_export(__PHPUNIT_PHAR__, true); + } else { + $phar = '\'\''; + } + + $data = var_export(serialize($test->providedData()), true); + $dataName = var_export($test->dataName(), true); + $dependencyInput = var_export(serialize($test->dependencyInput()), true); + $includePath = var_export(get_include_path(), true); + // must do these fixes because TestCaseMethod.tpl has unserialize('{data}') in it, and we can't break BC + // the lines above used to use addcslashes() rather than var_export(), which breaks null byte escape sequences + $data = "'." . $data . ".'"; + $dataName = "'.(" . $dataName . ").'"; + $dependencyInput = "'." . $dependencyInput . ".'"; + $includePath = "'." . $includePath . ".'"; + $offset = hrtime(); + $serializedConfiguration = $this->saveConfigurationForChildProcess(); + $processResultFile = tempnam(sys_get_temp_dir(), 'phpunit_'); + + $file = $class->getFileName(); + + assert($file !== false); + + $var = [ + 'bootstrap' => $bootstrap, + 'composerAutoload' => $composerAutoload, + 'phar' => $phar, + 'filename' => $file, + 'className' => $class->getName(), + 'methodName' => $test->name(), + 'collectCodeCoverageInformation' => $coverage, + 'data' => $data, + 'dataName' => $dataName, + 'dependencyInput' => $dependencyInput, + 'constants' => $constants, + 'globals' => $globals, + 'include_path' => $includePath, + 'included_files' => $includedFiles, + 'iniSettings' => $iniSettings, + 'name' => $test->name(), + 'offsetSeconds' => (string) $offset[0], + 'offsetNanoseconds' => (string) $offset[1], + 'serializedConfiguration' => $serializedConfiguration, + 'processResultFile' => $processResultFile, + ]; + + $template = new Template(__DIR__ . '/templates/method.tpl'); + + $template->setVar($var); + + $code = $template->render(); + + assert($code !== ''); + + JobRunnerRegistry::runTestJob(new Job($code, requiresXdebug: $requiresXdebug), $processResultFile, $test); + + @unlink($serializedConfiguration); + } + + /** + * @throws ProcessIsolationException + */ + private function saveConfigurationForChildProcess(): string + { + $path = tempnam(sys_get_temp_dir(), 'phpunit_'); + + if ($path === false) { + throw new ProcessIsolationException; + } + + if (!ConfigurationRegistry::saveTo($path)) { + throw new ProcessIsolationException; + } + + return $path; + } +} diff --git a/src/Framework/TestRunner/TestRunner.php b/src/Framework/TestRunner/TestRunner.php new file mode 100644 index 00000000000..e6cf03f6b1c --- /dev/null +++ b/src/Framework/TestRunner/TestRunner.php @@ -0,0 +1,395 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_diff_assoc; +use function array_intersect; +use function array_unique; +use function assert; +use function extension_loaded; +use function sprintf; +use function xdebug_is_debugger_active; +use AssertionError; +use PHPUnit\Event\Facade; +use PHPUnit\Metadata\Api\CodeCoverage as CodeCoverageMetadataApi; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\Runner\Exception; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException; +use SebastianBergmann\CodeCoverage\InvalidArgumentException; +use SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use SebastianBergmann\Invoker\Invoker; +use SebastianBergmann\Invoker\TimeoutException; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestRunner +{ + private ?bool $timeLimitCanBeEnforced = null; + private readonly Configuration $configuration; + + public function __construct() + { + $this->configuration = ConfigurationRegistry::get(); + } + + /** + * @throws Exception + * @throws InvalidArgumentException + * @throws UnintentionallyCoveredCodeException + */ + public function run(TestCase $test): void + { + Assert::resetCount(); + + $codeCoverageMetadataApi = new CodeCoverageMetadataApi; + + $coversTargets = $codeCoverageMetadataApi->coversTargets( + $test::class, + $test->name(), + ); + + $usesTargets = $codeCoverageMetadataApi->usesTargets( + $test::class, + $test->name(), + ); + + $shouldCodeCoverageBeCollected = $codeCoverageMetadataApi->shouldCodeCoverageBeCollectedFor($test); + + $this->performSanityChecks($test, $coversTargets, $usesTargets, $shouldCodeCoverageBeCollected); + + $error = false; + $failure = false; + $incomplete = false; + $risky = false; + $skipped = false; + + if ($this->shouldErrorHandlerBeUsed($test)) { + ErrorHandler::instance()->enable($test); + } + + $collectCodeCoverage = CodeCoverage::instance()->isActive() && + $shouldCodeCoverageBeCollected; + + if ($collectCodeCoverage) { + CodeCoverage::instance()->start($test); + } + + try { + if ($this->canTimeLimitBeEnforced() && + $this->shouldTimeLimitBeEnforced($test)) { + $risky = $this->runTestWithTimeout($test); + } else { + $test->runBare(); + } + } catch (AssertionFailedError $e) { + $failure = true; + + if ($e instanceof IncompleteTestError) { + $incomplete = true; + } elseif ($e instanceof SkippedTest) { + $skipped = true; + } + } catch (AssertionError $e) { + $test->addToAssertionCount(1); + + $failure = true; + $frame = $e->getTrace()[0]; + + assert(isset($frame['file'])); + assert(isset($frame['line'])); + + $e = new AssertionFailedError( + sprintf( + '%s in %s:%s', + $e->getMessage(), + $frame['file'], + $frame['line'], + ), + ); + } catch (Throwable $e) { + $error = true; + } + + $test->addToAssertionCount(Assert::getCount()); + + if ($this->configuration->reportUselessTests() && + !$test->doesNotPerformAssertions() && + $test->numberOfAssertionsPerformed() === 0) { + $risky = true; + } + + if (!$error && !$failure && !$incomplete && !$skipped && !$risky && + $this->configuration->requireCoverageMetadata() && + !$this->hasCoverageMetadata($test::class, $test->name())) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + 'This test does not define a code coverage target but is expected to do so', + ); + + $risky = true; + } + + if ($collectCodeCoverage) { + $append = !$risky && !$incomplete && !$skipped; + + if (!$append) { + $coversTargets = false; + $usesTargets = null; + } + + try { + CodeCoverage::instance()->stop( + $append, + $coversTargets, + $usesTargets, + ); + } catch (UnintentionallyCoveredCodeException $cce) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + 'This test executed code that is not listed as code to be covered or used:' . + PHP_EOL . + $cce->getMessage(), + ); + } catch (CodeCoverageException $cce) { + $error = true; + + $e = $e ?? $cce; + } + } + + ErrorHandler::instance()->disable(); + + if (!$error && + !$incomplete && + !$skipped && + $this->configuration->reportUselessTests() && + !$test->doesNotPerformAssertions() && + $test->numberOfAssertionsPerformed() === 0) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + 'This test did not perform any assertions', + ); + } + + if ($test->doesNotPerformAssertions() && + $test->numberOfAssertionsPerformed() > 0) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + sprintf( + 'This test is not expected to perform assertions but performed %d assertion%s', + $test->numberOfAssertionsPerformed(), + $test->numberOfAssertionsPerformed() > 1 ? 's' : '', + ), + ); + } + + if ($test->hasUnexpectedOutput()) { + Facade::emitter()->testPrintedUnexpectedOutput($test->output()); + } + + if ($this->configuration->disallowTestOutput() && $test->hasUnexpectedOutput()) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + sprintf( + 'Test code or tested code printed unexpected output: %s', + $test->output(), + ), + ); + } + + if ($test->wasPrepared()) { + Facade::emitter()->testFinished( + $test->valueObjectForEvents(), + $test->numberOfAssertionsPerformed(), + ); + } + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + private function hasCoverageMetadata(string $className, string $methodName): bool + { + foreach (MetadataRegistry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversNamespace()) { + return true; + } + + if ($metadata->isCoversTrait()) { + return true; + } + + if ($metadata->isCoversClass()) { + return true; + } + + if ($metadata->isCoversClassesThatExtendClass()) { + return true; + } + + if ($metadata->isCoversClassesThatImplementInterface()) { + return true; + } + + if ($metadata->isCoversMethod()) { + return true; + } + + if ($metadata->isCoversFunction()) { + return true; + } + + if ($metadata->isCoversNothing()) { + return true; + } + } + + return false; + } + + private function canTimeLimitBeEnforced(): bool + { + if ($this->timeLimitCanBeEnforced !== null) { + return $this->timeLimitCanBeEnforced; + } + + $this->timeLimitCanBeEnforced = (new Invoker)->canInvokeWithTimeout(); + + return $this->timeLimitCanBeEnforced; + } + + private function shouldTimeLimitBeEnforced(TestCase $test): bool + { + if (!$this->configuration->enforceTimeLimit()) { + return false; + } + + if (!(($this->configuration->defaultTimeLimit() > 0 || $test->size()->isKnown()))) { + return false; + } + + if (extension_loaded('xdebug') && xdebug_is_debugger_active()) { + return false; + } + + return true; + } + + /** + * @throws Throwable + */ + private function runTestWithTimeout(TestCase $test): bool + { + $_timeout = $this->configuration->defaultTimeLimit(); + $testSize = $test->size(); + + if ($testSize->isSmall()) { + $_timeout = $this->configuration->timeoutForSmallTests(); + } elseif ($testSize->isMedium()) { + $_timeout = $this->configuration->timeoutForMediumTests(); + } elseif ($testSize->isLarge()) { + $_timeout = $this->configuration->timeoutForLargeTests(); + } + + try { + (new Invoker)->invoke([$test, 'runBare'], [], $_timeout); + } catch (TimeoutException) { + Facade::emitter()->testConsideredRisky( + $test->valueObjectForEvents(), + sprintf( + 'This test was aborted after %d second%s', + $_timeout, + $_timeout !== 1 ? 's' : '', + ), + ); + + return true; + } + + return false; + } + + private function shouldErrorHandlerBeUsed(TestCase $test): bool + { + if (MetadataRegistry::parser()->forMethod($test::class, $test->name())->isWithoutErrorHandler()->isNotEmpty()) { + return false; + } + + return true; + } + + private function performSanityChecks(TestCase $test, TargetCollection $coversTargets, TargetCollection $usesTargets, bool $shouldCodeCoverageBeCollected): void + { + if (!$shouldCodeCoverageBeCollected) { + if ($coversTargets->isNotEmpty() || $usesTargets->isNotEmpty()) { + Facade::emitter()->testTriggeredPhpunitWarning( + $test->valueObjectForEvents(), + '#[Covers*] and #[Uses*] attributes do not have an effect when the #[CoversNothing] attribute is used', + ); + } + } + + $coversAsString = []; + $usesAsString = []; + + foreach ($coversTargets as $coversTarget) { + $coversAsString[] = $coversTarget->description(); + } + + foreach ($usesTargets as $usesTarget) { + $usesAsString[] = $usesTarget->description(); + } + + $coversDuplicates = array_unique(array_diff_assoc($coversAsString, array_unique($coversAsString))); + $usesDuplicates = array_unique(array_diff_assoc($usesAsString, array_unique($usesAsString))); + $coversAndUses = array_intersect($coversAsString, $usesAsString); + + foreach ($coversDuplicates as $target) { + Facade::emitter()->testTriggeredPhpunitWarning( + $test->valueObjectForEvents(), + sprintf( + '%s is targeted multiple times by the same "Covers" attribute', + $target, + ), + ); + } + + foreach ($usesDuplicates as $target) { + Facade::emitter()->testTriggeredPhpunitWarning( + $test->valueObjectForEvents(), + sprintf( + '%s is targeted multiple times by the same "Uses" attribute', + $target, + ), + ); + } + + foreach ($coversAndUses as $target) { + Facade::emitter()->testTriggeredPhpunitWarning( + $test->valueObjectForEvents(), + sprintf( + '%s is targeted by both "Covers" and "Uses" attributes', + $target, + ), + ); + } + } +} diff --git a/src/Framework/TestRunner/templates/method.tpl b/src/Framework/TestRunner/templates/method.tpl new file mode 100644 index 00000000000..ed45805afeb --- /dev/null +++ b/src/Framework/TestRunner/templates/method.tpl @@ -0,0 +1,137 @@ +initForIsolation( + PHPUnit\Event\Telemetry\HRTime::fromSecondsAndNanoseconds( + {offsetSeconds}, + {offsetNanoseconds} + ), + ); + + require_once '{filename}'; + + $configuration = ConfigurationRegistry::get(); + + if ({collectCodeCoverageInformation}) { + CodeCoverage::instance()->init($configuration, CodeCoverageFilterRegistry::instance(), true); + } + + $deprecationTriggers = [ + 'functions' => [], + 'methods' => [], + ]; + + foreach ($configuration->source()->deprecationTriggers()['functions'] as $function) { + $deprecationTriggers['functions'][] = $function; + } + + foreach ($configuration->source()->deprecationTriggers()['methods'] as $method) { + [$className, $methodName] = explode('::', $method); + + $deprecationTriggers['methods'][] = [ + 'className' => $className, + 'methodName' => $methodName, + ]; + } + + ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers); + + $test = new {className}('{methodName}'); + + $test->setData('{dataName}', unserialize('{data}')); + $test->setDependencyInput(unserialize('{dependencyInput}')); + $test->setInIsolation(true); + + ob_end_clean(); + + $test->run(); + + $output = ''; + + if (!$test->expectsOutput()) { + $output = $test->output(); + } + + ini_set('xdebug.scream', '0'); + + // Not every STDOUT target stream is rewindable + $hasRewound = @rewind(STDOUT); + + if ($hasRewound && $stdout = @stream_get_contents(STDOUT)) { + $output = $stdout . $output; + $streamMetaData = stream_get_meta_data(STDOUT); + + if (!empty($streamMetaData['stream_type']) && 'STDIO' === $streamMetaData['stream_type']) { + @ftruncate(STDOUT, 0); + @rewind(STDOUT); + } + } + + file_put_contents( + '{processResultFile}', + serialize( + (object)[ + 'testResult' => $test->result(), + 'codeCoverage' => {collectCodeCoverageInformation} ? CodeCoverage::instance()->codeCoverage() : null, + 'numAssertions' => $test->numberOfAssertionsPerformed(), + 'output' => $output, + 'events' => $dispatcher->flush(), + 'passedTests' => PassedTests::instance() + ] + ) + ); +} + +function __phpunit_error_handler($errno, $errstr, $errfile, $errline) +{ + return true; +} + +set_error_handler('__phpunit_error_handler'); + +{constants} +{included_files} +{globals} + +restore_error_handler(); + +ConfigurationRegistry::loadFrom('{serializedConfiguration}'); +(new PhpHandler)->handle(ConfigurationRegistry::get()->php()); + +if ('{bootstrap}' !== '') { + require_once '{bootstrap}'; +} + +__phpunit_run_isolated_test(); diff --git a/src/Framework/TestSize/Known.php b/src/Framework/TestSize/Known.php new file mode 100644 index 00000000000..a61a05a0017 --- /dev/null +++ b/src/Framework/TestSize/Known.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class Known extends TestSize +{ + public function isKnown(): true + { + return true; + } + + abstract public function isGreaterThan(self $other): bool; +} diff --git a/src/Framework/TestSize/Large.php b/src/Framework/TestSize/Large.php new file mode 100644 index 00000000000..71a254ed470 --- /dev/null +++ b/src/Framework/TestSize/Large.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Large extends Known +{ + public function isLarge(): true + { + return true; + } + + public function isGreaterThan(TestSize $other): bool + { + return !$other->isLarge(); + } + + public function asString(): string + { + return 'large'; + } +} diff --git a/src/Framework/TestSize/Medium.php b/src/Framework/TestSize/Medium.php new file mode 100644 index 00000000000..beb574463dd --- /dev/null +++ b/src/Framework/TestSize/Medium.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Medium extends Known +{ + public function isMedium(): true + { + return true; + } + + public function isGreaterThan(TestSize $other): bool + { + return $other->isSmall(); + } + + public function asString(): string + { + return 'medium'; + } +} diff --git a/src/Framework/TestSize/Small.php b/src/Framework/TestSize/Small.php new file mode 100644 index 00000000000..76bdec64344 --- /dev/null +++ b/src/Framework/TestSize/Small.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Small extends Known +{ + public function isSmall(): true + { + return true; + } + + public function isGreaterThan(TestSize $other): bool + { + return false; + } + + public function asString(): string + { + return 'small'; + } +} diff --git a/src/Framework/TestSize/TestSize.php b/src/Framework/TestSize/TestSize.php new file mode 100644 index 00000000000..c341d8b934b --- /dev/null +++ b/src/Framework/TestSize/TestSize.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class TestSize +{ + public static function unknown(): self + { + return new Unknown; + } + + public static function small(): self + { + return new Small; + } + + public static function medium(): self + { + return new Medium; + } + + public static function large(): self + { + return new Large; + } + + /** + * @phpstan-assert-if-true Known $this + */ + public function isKnown(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Unknown $this + */ + public function isUnknown(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Small $this + */ + public function isSmall(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Medium $this + */ + public function isMedium(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Large $this + */ + public function isLarge(): bool + { + return false; + } + + abstract public function asString(): string; +} diff --git a/src/Framework/TestSize/Unknown.php b/src/Framework/TestSize/Unknown.php new file mode 100644 index 00000000000..daf1e7d35ba --- /dev/null +++ b/src/Framework/TestSize/Unknown.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Unknown extends TestSize +{ + public function isUnknown(): true + { + return true; + } + + public function asString(): string + { + return 'unknown'; + } +} diff --git a/src/Framework/TestStatus/Deprecation.php b/src/Framework/TestStatus/Deprecation.php new file mode 100644 index 00000000000..0bc4957ca56 --- /dev/null +++ b/src/Framework/TestStatus/Deprecation.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Deprecation extends Known +{ + public function isDeprecation(): true + { + return true; + } + + public function asInt(): int + { + return 4; + } + + public function asString(): string + { + return 'deprecation'; + } +} diff --git a/src/Framework/TestStatus/Error.php b/src/Framework/TestStatus/Error.php new file mode 100644 index 00000000000..35e368e813c --- /dev/null +++ b/src/Framework/TestStatus/Error.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Error extends Known +{ + public function isError(): true + { + return true; + } + + public function asInt(): int + { + return 8; + } + + public function asString(): string + { + return 'error'; + } +} diff --git a/src/Framework/TestStatus/Failure.php b/src/Framework/TestStatus/Failure.php new file mode 100644 index 00000000000..ec5996c90cf --- /dev/null +++ b/src/Framework/TestStatus/Failure.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Failure extends Known +{ + public function isFailure(): true + { + return true; + } + + public function asInt(): int + { + return 7; + } + + public function asString(): string + { + return 'failure'; + } +} diff --git a/src/Framework/TestStatus/Incomplete.php b/src/Framework/TestStatus/Incomplete.php new file mode 100644 index 00000000000..92f86fba86d --- /dev/null +++ b/src/Framework/TestStatus/Incomplete.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Incomplete extends Known +{ + public function isIncomplete(): true + { + return true; + } + + public function asInt(): int + { + return 2; + } + + public function asString(): string + { + return 'incomplete'; + } +} diff --git a/src/Framework/TestStatus/Known.php b/src/Framework/TestStatus/Known.php new file mode 100644 index 00000000000..4d9e5e8b4b7 --- /dev/null +++ b/src/Framework/TestStatus/Known.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Known extends TestStatus +{ + public function isKnown(): true + { + return true; + } +} diff --git a/src/Framework/TestStatus/Notice.php b/src/Framework/TestStatus/Notice.php new file mode 100644 index 00000000000..be9bd4c03d7 --- /dev/null +++ b/src/Framework/TestStatus/Notice.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Notice extends Known +{ + public function isNotice(): true + { + return true; + } + + public function asInt(): int + { + return 3; + } + + public function asString(): string + { + return 'notice'; + } +} diff --git a/src/Framework/TestStatus/Risky.php b/src/Framework/TestStatus/Risky.php new file mode 100644 index 00000000000..63bde2972c2 --- /dev/null +++ b/src/Framework/TestStatus/Risky.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Risky extends Known +{ + public function isRisky(): true + { + return true; + } + + public function asInt(): int + { + return 5; + } + + public function asString(): string + { + return 'risky'; + } +} diff --git a/src/Framework/TestStatus/Skipped.php b/src/Framework/TestStatus/Skipped.php new file mode 100644 index 00000000000..9539e9e0d82 --- /dev/null +++ b/src/Framework/TestStatus/Skipped.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Skipped extends Known +{ + public function isSkipped(): true + { + return true; + } + + public function asInt(): int + { + return 1; + } + + public function asString(): string + { + return 'skipped'; + } +} diff --git a/src/Framework/TestStatus/Success.php b/src/Framework/TestStatus/Success.php new file mode 100644 index 00000000000..7891505165e --- /dev/null +++ b/src/Framework/TestStatus/Success.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Success extends Known +{ + public function isSuccess(): true + { + return true; + } + + public function asInt(): int + { + return 0; + } + + public function asString(): string + { + return 'success'; + } +} diff --git a/src/Framework/TestStatus/TestStatus.php b/src/Framework/TestStatus/TestStatus.php new file mode 100644 index 00000000000..81870826bd8 --- /dev/null +++ b/src/Framework/TestStatus/TestStatus.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class TestStatus +{ + private string $message; + + public static function from(int $status): self + { + return match ($status) { + 0 => self::success(), + 1 => self::skipped(), + 2 => self::incomplete(), + 3 => self::notice(), + 4 => self::deprecation(), + 5 => self::risky(), + 6 => self::warning(), + 7 => self::failure(), + 8 => self::error(), + default => self::unknown(), + }; + } + + public static function unknown(): self + { + return new Unknown; + } + + public static function success(): self + { + return new Success; + } + + public static function skipped(string $message = ''): self + { + return new Skipped($message); + } + + public static function incomplete(string $message = ''): self + { + return new Incomplete($message); + } + + public static function notice(string $message = ''): self + { + return new Notice($message); + } + + public static function deprecation(string $message = ''): self + { + return new Deprecation($message); + } + + public static function failure(string $message = ''): self + { + return new Failure($message); + } + + public static function error(string $message = ''): self + { + return new Error($message); + } + + public static function warning(string $message = ''): self + { + return new Warning($message); + } + + public static function risky(string $message = ''): self + { + return new Risky($message); + } + + private function __construct(string $message = '') + { + $this->message = $message; + } + + /** + * @phpstan-assert-if-true Known $this + */ + public function isKnown(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Unknown $this + */ + public function isUnknown(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Success $this + */ + public function isSuccess(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Skipped $this + */ + public function isSkipped(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Incomplete $this + */ + public function isIncomplete(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Notice $this + */ + public function isNotice(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Deprecation $this + */ + public function isDeprecation(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Failure $this + */ + public function isFailure(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Error $this + */ + public function isError(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Warning $this + */ + public function isWarning(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Risky $this + */ + public function isRisky(): bool + { + return false; + } + + public function message(): string + { + return $this->message; + } + + public function isMoreImportantThan(self $other): bool + { + return $this->asInt() > $other->asInt(); + } + + abstract public function asInt(): int; + + abstract public function asString(): string; +} diff --git a/src/Framework/TestStatus/Unknown.php b/src/Framework/TestStatus/Unknown.php new file mode 100644 index 00000000000..a5c1309b563 --- /dev/null +++ b/src/Framework/TestStatus/Unknown.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Unknown extends TestStatus +{ + public function isUnknown(): true + { + return true; + } + + public function asInt(): int + { + return -1; + } + + public function asString(): string + { + return 'unknown'; + } +} diff --git a/src/Framework/TestStatus/Warning.php b/src/Framework/TestStatus/Warning.php new file mode 100644 index 00000000000..c091262b8b8 --- /dev/null +++ b/src/Framework/TestStatus/Warning.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Warning extends Known +{ + public function isWarning(): true + { + return true; + } + + public function asInt(): int + { + return 6; + } + + public function asString(): string + { + return 'warning'; + } +} diff --git a/src/Framework/TestSuite.php b/src/Framework/TestSuite.php new file mode 100644 index 00000000000..acf9e2b763e --- /dev/null +++ b/src/Framework/TestSuite.php @@ -0,0 +1,758 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_EOL; +use function array_merge; +use function array_pop; +use function array_reverse; +use function assert; +use function call_user_func; +use function class_exists; +use function count; +use function implode; +use function is_callable; +use function is_file; +use function is_subclass_of; +use function sprintf; +use function str_ends_with; +use function str_starts_with; +use function trim; +use Iterator; +use IteratorAggregate; +use PHPUnit\Event; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Metadata\Api\Dependencies; +use PHPUnit\Metadata\Api\Groups; +use PHPUnit\Metadata\Api\HookMethods; +use PHPUnit\Metadata\Api\Requirements; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Runner\Exception as RunnerException; +use PHPUnit\Runner\Filter\Factory; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use PHPUnit\Runner\TestSuiteLoader; +use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; +use PHPUnit\Util\Filter; +use PHPUnit\Util\Reflection; +use PHPUnit\Util\Test as TestUtil; +use ReflectionClass; +use ReflectionMethod; +use SebastianBergmann\CodeCoverage\InvalidArgumentException; +use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use Throwable; + +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +class TestSuite implements IteratorAggregate, Reorderable, Test +{ + /** + * @var non-empty-string + */ + private string $name; + + /** + * @var array> + */ + private array $groups = []; + + /** + * @var ?list + */ + private ?array $requiredTests = null; + + /** + * @var list + */ + private array $tests = []; + + /** + * @var ?list + */ + private ?array $providedTests = null; + private ?Factory $iteratorFilter = null; + private bool $wasRun = false; + + /** + * @param non-empty-string $name + */ + public static function empty(string $name): static + { + return new static($name); + } + + /** + * @param ReflectionClass $class + * @param list $groups + */ + public static function fromClassReflector(ReflectionClass $class, array $groups = []): static + { + $testSuite = new static($class->getName()); + + foreach (Reflection::publicMethodsDeclaredDirectlyInTestClass($class) as $method) { + if (!TestUtil::isTestMethod($method)) { + continue; + } + + if ((new HookMethods)->isHookMethod($method)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Method %s::%s() cannot be used both as a hook method and as a test method', + $class->getName(), + $method->getName(), + ), + ); + + continue; + } + + $testSuite->addTestMethod($class, $method, $groups); + } + + if ($testSuite->isEmpty()) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'No tests found in class "%s".', + $class->getName(), + ), + ); + } + + return $testSuite; + } + + /** + * @param non-empty-string $name + */ + final private function __construct(string $name) + { + $this->name = $name; + } + + /** + * Adds a test to the suite. + * + * @param list $groups + */ + public function addTest(Test $test, array $groups = []): void + { + if ($test instanceof self) { + $this->tests[] = $test; + + $this->clearCaches(); + + return; + } + + assert($test instanceof TestCase || $test instanceof PhptTestCase); + + $this->tests[] = $test; + + $this->clearCaches(); + + if ($this->containsOnlyVirtualGroups($groups)) { + $groups[] = 'default'; + } + + if ($test instanceof TestCase) { + $id = $test->valueObjectForEvents()->id(); + + $test->setGroups($groups); + } else { + $id = $test->valueObjectForEvents()->id(); + } + + foreach ($groups as $group) { + if (!isset($this->groups[$group])) { + $this->groups[$group] = [$id]; + } else { + $this->groups[$group][] = $id; + } + } + } + + /** + * Adds the tests from the given class to the suite. + * + * @param ReflectionClass $testClass + * @param list $groups + * + * @throws Exception + */ + public function addTestSuite(ReflectionClass $testClass, array $groups = []): void + { + if ($testClass->isAbstract()) { + throw new Exception( + sprintf( + 'Class %s is abstract', + $testClass->getName(), + ), + ); + } + + if (!$testClass->isSubclassOf(TestCase::class)) { + throw new Exception( + sprintf( + 'Class %s is not a subclass of %s', + $testClass->getName(), + TestCase::class, + ), + ); + } + + $this->addTest(self::fromClassReflector($testClass, $groups), $groups); + } + + /** + * Wraps both addTest() and addTestSuite + * as well as the separate import statements for the user's convenience. + * + * If the named file cannot be read or there are no new tests that can be + * added, a PHPUnit\Framework\WarningTestCase will be created instead, + * leaving the current test run untouched. + * + * @param list $groups + * + * @throws Exception + */ + public function addTestFile(string $filename, array $groups = []): void + { + try { + if (str_ends_with($filename, '.phpt') && is_file($filename)) { + $this->addTest(new PhptTestCase($filename)); + } else { + $this->addTestSuite( + (new TestSuiteLoader)->load($filename), + $groups, + ); + } + } catch (RunnerException $e) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + $e->getMessage(), + ); + } + } + + /** + * Wrapper for addTestFile() that adds multiple test files. + * + * @param iterable $fileNames + * + * @throws Exception + */ + public function addTestFiles(iterable $fileNames): void + { + foreach ($fileNames as $filename) { + $this->addTestFile((string) $filename); + } + } + + /** + * Counts the number of test cases that will be run by this test. + */ + public function count(): int + { + $numTests = 0; + + foreach ($this as $test) { + $numTests += count($test); + } + + return $numTests; + } + + public function isEmpty(): bool + { + foreach ($this as $test) { + if (count($test) !== 0) { + return false; + } + } + + return true; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + + /** + * @return array> + */ + public function groups(): array + { + return $this->groups; + } + + /** + * @return list + */ + public function collect(): array + { + $tests = []; + + foreach ($this as $test) { + if ($test instanceof self) { + $tests = array_merge($tests, $test->collect()); + + continue; + } + + assert($test instanceof TestCase || $test instanceof PhptTestCase); + + $tests[] = $test; + } + + return $tests; + } + + /** + * @throws Event\RuntimeException + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws UnintentionallyCoveredCodeException + */ + public function run(): void + { + if ($this->wasRun) { + // @codeCoverageIgnoreStart + throw new Exception('The tests aggregated by this TestSuite were already run'); + // @codeCoverageIgnoreEnd + } + + $this->wasRun = true; + + if ($this->isEmpty()) { + return; + } + + $emitter = Event\Facade::emitter(); + $testSuiteValueObjectForEvents = Event\TestSuite\TestSuiteBuilder::from($this); + + $emitter->testSuiteStarted($testSuiteValueObjectForEvents); + + if (!$this->invokeMethodsBeforeFirstTest($emitter, $testSuiteValueObjectForEvents)) { + return; + } + + /** @var list $tests */ + $tests = []; + + foreach ($this as $test) { + $tests[] = $test; + } + + $tests = array_reverse($tests); + + $this->tests = []; + $this->groups = []; + + while (($test = array_pop($tests)) !== null) { + if (TestResultFacade::shouldStop()) { + $emitter->testRunnerExecutionAborted(); + + break; + } + + $test->run(); + } + + $this->invokeMethodsAfterLastTest($emitter); + + $emitter->testSuiteFinished($testSuiteValueObjectForEvents); + } + + /** + * Returns the tests as an enumeration. + * + * @return list + */ + public function tests(): array + { + return $this->tests; + } + + /** + * Set tests of the test suite. + * + * @param list $tests + */ + public function setTests(array $tests): void + { + $this->tests = $tests; + } + + /** + * Mark the test suite as skipped. + * + * @throws SkippedTestSuiteError + */ + public function markTestSuiteSkipped(string $message = ''): never + { + throw new SkippedTestSuiteError($message); + } + + /** + * Returns an iterator for this test suite. + */ + public function getIterator(): Iterator + { + $iterator = new TestSuiteIterator($this); + + if ($this->iteratorFilter !== null) { + $iterator = $this->iteratorFilter->factory($iterator, $this); + } + + return $iterator; + } + + public function injectFilter(Factory $filter): void + { + $this->iteratorFilter = $filter; + + foreach ($this as $test) { + if ($test instanceof self) { + $test->injectFilter($filter); + } + } + } + + /** + * @return list + */ + public function provides(): array + { + if ($this->providedTests === null) { + $this->providedTests = []; + + if (is_callable($this->sortId(), true)) { + $this->providedTests[] = new ExecutionOrderDependency($this->sortId()); + } + + foreach ($this->tests as $test) { + if (!$test instanceof Reorderable) { + // @codeCoverageIgnoreStart + continue; + // @codeCoverageIgnoreEnd + } + + $this->providedTests = ExecutionOrderDependency::mergeUnique($this->providedTests, $test->provides()); + } + } + + return $this->providedTests; + } + + /** + * @return list + */ + public function requires(): array + { + if ($this->requiredTests === null) { + $this->requiredTests = []; + + foreach ($this->tests as $test) { + if (!$test instanceof Reorderable) { + // @codeCoverageIgnoreStart + continue; + // @codeCoverageIgnoreEnd + } + + $this->requiredTests = ExecutionOrderDependency::mergeUnique( + ExecutionOrderDependency::filterInvalid($this->requiredTests), + $test->requires(), + ); + } + + $this->requiredTests = ExecutionOrderDependency::diff($this->requiredTests, $this->provides()); + } + + return $this->requiredTests; + } + + public function sortId(): string + { + return $this->name() . '::class'; + } + + /** + * @phpstan-assert-if-true class-string $this->name + */ + public function isForTestClass(): bool + { + return class_exists($this->name, false) && is_subclass_of($this->name, TestCase::class); + } + + /** + * @param ReflectionClass $class + * @param list $groups + * + * @throws Exception + */ + protected function addTestMethod(ReflectionClass $class, ReflectionMethod $method, array $groups): void + { + $className = $class->getName(); + $methodName = $method->getName(); + + try { + $test = (new TestBuilder)->build($class, $methodName, $groups); + } catch (InvalidDataProviderException $e) { + if ($e->getProviderLabel() === null) { + $message = sprintf( + "The data provider specified for %s::%s is invalid\n%s", + $className, + $methodName, + $this->exceptionToString($e), + ); + } else { + $message = sprintf( + "The data provider %s specified for %s::%s is invalid\n%s", + $e->getProviderLabel(), + $className, + $methodName, + $this->exceptionToString($e), + ); + } + + Event\Facade::emitter()->testTriggeredPhpunitError( + new TestMethod( + $className, + $methodName, + $class->getFileName(), + $method->getStartLine(), + Event\Code\TestDoxBuilder::fromClassNameAndMethodName( + $className, + $methodName, + ), + MetadataCollection::fromArray([]), + Event\TestData\TestDataCollection::fromArray([]), + ), + $message, + ); + + return; + } + + if ($test instanceof TestCase || $test instanceof DataProviderTestSuite) { + $test->setDependencies( + Dependencies::dependencies($class->getName(), $methodName), + ); + } + + $this->addTest( + $test, + array_merge( + $groups, + (new Groups)->groups($class->getName(), $methodName), + ), + ); + } + + private function clearCaches(): void + { + $this->providedTests = null; + $this->requiredTests = null; + } + + /** + * @param list $groups + */ + private function containsOnlyVirtualGroups(array $groups): bool + { + foreach ($groups as $group) { + if (!str_starts_with($group, '__phpunit_')) { + return false; + } + } + + return true; + } + + private function methodDoesNotExistOrIsDeclaredInTestCase(string $methodName): bool + { + $reflector = new ReflectionClass($this->name); + + return !$reflector->hasMethod($methodName) || + $reflector->getMethod($methodName)->getDeclaringClass()->getName() === TestCase::class; + } + + /** + * @throws Exception + */ + private function exceptionToString(InvalidDataProviderException $e): string + { + $message = $e->getMessage(); + + if (trim($message) === '') { + $message = ''; + } + + return sprintf( + "%s\n%s", + $message, + Filter::stackTraceFromThrowableAsString($e), + ); + } + + /** + * @throws Exception + * @throws NoPreviousThrowableException + */ + private function invokeMethodsBeforeFirstTest(Event\Emitter $emitter, Event\TestSuite\TestSuite $testSuiteValueObjectForEvents): bool + { + if (!$this->isForTestClass()) { + return true; + } + + $methods = (new HookMethods)->hookMethods($this->name)['beforeClass']->methodNamesSortedByPriority(); + $calledMethods = []; + $emitCalledEvent = true; + $result = true; + + foreach ($methods as $method) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($method)) { + continue; + } + + $calledMethod = new Event\Code\ClassMethod( + $this->name, + $method, + ); + + try { + $missingRequirements = (new Requirements)->requirementsNotSatisfiedFor($this->name, $method); + + if ($missingRequirements !== []) { + $emitCalledEvent = false; + + $this->markTestSuiteSkipped(implode(PHP_EOL, $missingRequirements)); + } + + call_user_func([$this->name, $method]); + } catch (Throwable $t) { + } + + if ($emitCalledEvent) { + $emitter->beforeFirstTestMethodCalled( + $this->name, + $calledMethod, + ); + + $calledMethods[] = $calledMethod; + } + + if (isset($t) && $t instanceof SkippedTest) { + $emitter->testSuiteSkipped( + $testSuiteValueObjectForEvents, + $t->getMessage(), + ); + + return false; + } + + if (isset($t)) { + if ($t instanceof AssertionFailedError) { + $emitter->beforeFirstTestMethodFailed( + $this->name, + $calledMethod, + Event\Code\ThrowableBuilder::from($t), + ); + } else { + $emitter->beforeFirstTestMethodErrored( + $this->name, + $calledMethod, + Event\Code\ThrowableBuilder::from($t), + ); + } + + $result = false; + } + } + + if ($calledMethods !== []) { + $emitter->beforeFirstTestMethodFinished( + $this->name, + ...$calledMethods, + ); + } + + if (!$result) { + $emitter->testSuiteFinished($testSuiteValueObjectForEvents); + } + + return $result; + } + + private function invokeMethodsAfterLastTest(Event\Emitter $emitter): void + { + if (!$this->isForTestClass()) { + return; + } + + $methods = (new HookMethods)->hookMethods($this->name)['afterClass']->methodNamesSortedByPriority(); + $calledMethods = []; + + foreach ($methods as $method) { + if ($this->methodDoesNotExistOrIsDeclaredInTestCase($method)) { + continue; + } + + $calledMethod = new Event\Code\ClassMethod( + $this->name, + $method, + ); + + try { + call_user_func([$this->name, $method]); + } catch (Throwable $t) { + } + + $emitter->afterLastTestMethodCalled( + $this->name, + $calledMethod, + ); + + $calledMethods[] = $calledMethod; + + if (isset($t)) { + if ($t instanceof AssertionFailedError) { + $emitter->afterLastTestMethodFailed( + $this->name, + $calledMethod, + Event\Code\ThrowableBuilder::from($t), + ); + } else { + $emitter->afterLastTestMethodErrored( + $this->name, + $calledMethod, + Event\Code\ThrowableBuilder::from($t), + ); + } + } + } + + if ($calledMethods !== []) { + $emitter->afterLastTestMethodFinished( + $this->name, + ...$calledMethods, + ); + } + } +} diff --git a/src/Framework/TestSuiteIterator.php b/src/Framework/TestSuiteIterator.php new file mode 100644 index 00000000000..3cbf431164a --- /dev/null +++ b/src/Framework/TestSuiteIterator.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function assert; +use function count; +use RecursiveIterator; + +/** + * @template-implements RecursiveIterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteIterator implements RecursiveIterator +{ + private int $position = 0; + + /** + * @var list + */ + private readonly array $tests; + + public function __construct(TestSuite $testSuite) + { + $this->tests = $testSuite->tests(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->tests); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Test + { + return $this->tests[$this->position]; + } + + public function next(): void + { + $this->position++; + } + + /** + * @throws NoChildTestSuiteException + */ + public function getChildren(): self + { + if (!$this->hasChildren()) { + throw new NoChildTestSuiteException( + 'The current item is not a TestSuite instance and therefore does not have any children.', + ); + } + + $current = $this->current(); + + assert($current instanceof TestSuite); + + return new self($current); + } + + public function hasChildren(): bool + { + return $this->valid() && $this->current() instanceof TestSuite; + } +} diff --git a/src/Logging/EventLogger.php b/src/Logging/EventLogger.php new file mode 100644 index 00000000000..738f3037799 --- /dev/null +++ b/src/Logging/EventLogger.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging; + +use const FILE_APPEND; +use const LOCK_EX; +use const PHP_EOL; +use const PHP_OS_FAMILY; +use function file_put_contents; +use function implode; +use function preg_split; +use function str_repeat; +use function strlen; +use PHPUnit\Event\Event; +use PHPUnit\Event\Tracer\Tracer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class EventLogger implements Tracer +{ + private string $path; + private bool $includeTelemetryInfo; + + public function __construct(string $path, bool $includeTelemetryInfo) + { + $this->path = $path; + $this->includeTelemetryInfo = $includeTelemetryInfo; + } + + public function trace(Event $event): void + { + $telemetryInfo = $this->telemetryInfo($event); + $indentation = PHP_EOL . str_repeat(' ', strlen($telemetryInfo)); + $flags = FILE_APPEND; + + if (!(PHP_OS_FAMILY === 'Windows' || PHP_OS_FAMILY === 'Darwin') || + $this->path !== 'php://stdout') { + $flags |= LOCK_EX; + } + + $lines = preg_split('/\r\n|\r|\n/', $event->asString()); + + if ($lines === false) { + $lines = []; + } + + file_put_contents( + $this->path, + $telemetryInfo . implode($indentation, $lines) . PHP_EOL, + $flags, + ); + } + + private function telemetryInfo(Event $event): string + { + if (!$this->includeTelemetryInfo) { + return ''; + } + + return $event->telemetryInfo()->asString() . ' '; + } +} diff --git a/src/Logging/JUnit/JunitXmlLogger.php b/src/Logging/JUnit/JunitXmlLogger.php new file mode 100644 index 00000000000..14a71b769de --- /dev/null +++ b/src/Logging/JUnit/JunitXmlLogger.php @@ -0,0 +1,462 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use const PHP_EOL; +use function assert; +use function basename; +use function is_int; +use function sprintf; +use function str_replace; +use function trim; +use DOMDocument; +use DOMElement; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Telemetry\Info; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Xml; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class JunitXmlLogger +{ + private readonly Printer $printer; + private DOMDocument $document; + private DOMElement $root; + + /** + * @var array + */ + private array $testSuites = []; + + /** + * @var array + */ + private array $testSuiteTests = [0]; + + /** + * @var array + */ + private array $testSuiteAssertions = [0]; + + /** + * @var array + */ + private array $testSuiteErrors = [0]; + + /** + * @var array + */ + private array $testSuiteFailures = [0]; + + /** + * @var array + */ + private array $testSuiteSkipped = [0]; + + /** + * @var array + */ + private array $testSuiteTimes = [0.0]; + private int $testSuiteLevel = 0; + private ?DOMElement $currentTestCase = null; + private ?HRTime $time = null; + private bool $prepared = false; + private bool $preparationFailed = false; + private ?string $unexpectedOutput = null; + + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + + $this->registerSubscribers($facade); + $this->createDocument(); + } + + public function flush(): void + { + $xml = $this->document->saveXML(); + + if ($xml === false) { + $xml = ''; + } + + $this->printer->print($xml); + $this->printer->flush(); + } + + public function testSuiteStarted(Started $event): void + { + $testSuite = $this->document->createElement('testsuite'); + $testSuite->setAttribute('name', $event->testSuite()->name()); + + if ($event->testSuite()->isForTestClass()) { + $testSuite->setAttribute('file', $event->testSuite()->file()); + } + + if ($this->testSuiteLevel > 0) { + $this->testSuites[$this->testSuiteLevel]->appendChild($testSuite); + } else { + $this->root->appendChild($testSuite); + } + + $this->testSuiteLevel++; + $this->testSuites[$this->testSuiteLevel] = $testSuite; + $this->testSuiteTests[$this->testSuiteLevel] = 0; + $this->testSuiteAssertions[$this->testSuiteLevel] = 0; + $this->testSuiteErrors[$this->testSuiteLevel] = 0; + $this->testSuiteFailures[$this->testSuiteLevel] = 0; + $this->testSuiteSkipped[$this->testSuiteLevel] = 0; + $this->testSuiteTimes[$this->testSuiteLevel] = 0.0; + } + + public function testSuiteFinished(): void + { + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'tests', + (string) $this->testSuiteTests[$this->testSuiteLevel], + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'assertions', + (string) $this->testSuiteAssertions[$this->testSuiteLevel], + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'errors', + (string) $this->testSuiteErrors[$this->testSuiteLevel], + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'failures', + (string) $this->testSuiteFailures[$this->testSuiteLevel], + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'skipped', + (string) $this->testSuiteSkipped[$this->testSuiteLevel], + ); + + $this->testSuites[$this->testSuiteLevel]->setAttribute( + 'time', + sprintf('%F', $this->testSuiteTimes[$this->testSuiteLevel]), + ); + + if ($this->testSuiteLevel > 1) { + $this->testSuiteTests[$this->testSuiteLevel - 1] += $this->testSuiteTests[$this->testSuiteLevel]; + $this->testSuiteAssertions[$this->testSuiteLevel - 1] += $this->testSuiteAssertions[$this->testSuiteLevel]; + $this->testSuiteErrors[$this->testSuiteLevel - 1] += $this->testSuiteErrors[$this->testSuiteLevel]; + $this->testSuiteFailures[$this->testSuiteLevel - 1] += $this->testSuiteFailures[$this->testSuiteLevel]; + $this->testSuiteSkipped[$this->testSuiteLevel - 1] += $this->testSuiteSkipped[$this->testSuiteLevel]; + $this->testSuiteTimes[$this->testSuiteLevel - 1] += $this->testSuiteTimes[$this->testSuiteLevel]; + } + + $this->testSuiteLevel--; + } + + /** + * @throws InvalidArgumentException + */ + public function testPreparationStarted(PreparationStarted $event): void + { + $this->createTestCase($event); + + $this->preparationFailed = false; + } + + public function testPreparationErrored(): void + { + $this->preparationFailed = true; + } + + public function testPreparationFailed(): void + { + $this->preparationFailed = true; + } + + public function testPrepared(): void + { + $this->prepared = true; + } + + public function testPrintedUnexpectedOutput(PrintedUnexpectedOutput $event): void + { + $this->unexpectedOutput = $event->output(); + } + + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + if (!$this->prepared || $this->preparationFailed) { + return; + } + + $this->handleFinish($event->telemetryInfo(), $event->numberOfAssertionsPerformed()); + } + + /** + * @throws InvalidArgumentException + */ + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->handleIncompleteOrSkipped($event); + } + + /** + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + $this->handleIncompleteOrSkipped($event); + } + + /** + * @throws InvalidArgumentException + */ + public function testErrored(Errored $event): void + { + $this->handleFault($event, 'error'); + + $this->testSuiteErrors[$this->testSuiteLevel]++; + } + + /** + * @throws InvalidArgumentException + */ + public function testFailed(Failed $event): void + { + $this->handleFault($event, 'failure'); + + $this->testSuiteFailures[$this->testSuiteLevel]++; + } + + /** + * @throws InvalidArgumentException + */ + private function handleFinish(Info $telemetryInfo, int $numberOfAssertionsPerformed): void + { + assert($this->currentTestCase !== null); + assert($this->time !== null); + + $time = $telemetryInfo->time()->duration($this->time)->asFloat(); + + $this->testSuiteAssertions[$this->testSuiteLevel] += $numberOfAssertionsPerformed; + + $this->currentTestCase->setAttribute( + 'assertions', + (string) $numberOfAssertionsPerformed, + ); + + $this->currentTestCase->setAttribute( + 'time', + sprintf('%F', $time), + ); + + if ($this->unexpectedOutput !== null) { + $systemOut = $this->document->createElement( + 'system-out', + Xml::prepareString($this->unexpectedOutput), + ); + + $this->currentTestCase->appendChild($systemOut); + } + + $this->testSuites[$this->testSuiteLevel]->appendChild( + $this->currentTestCase, + ); + + $this->testSuiteTests[$this->testSuiteLevel]++; + $this->testSuiteTimes[$this->testSuiteLevel] += $time; + + $this->currentTestCase = null; + $this->time = null; + $this->preparationFailed = false; + $this->prepared = false; + $this->unexpectedOutput = null; + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new TestSuiteStartedSubscriber($this), + new TestSuiteFinishedSubscriber($this), + new TestPreparationStartedSubscriber($this), + new TestPreparationErroredSubscriber($this), + new TestPreparationFailedSubscriber($this), + new TestPreparedSubscriber($this), + new TestPrintedUnexpectedOutputSubscriber($this), + new TestFinishedSubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestSkippedSubscriber($this), + new TestRunnerExecutionFinishedSubscriber($this), + ); + } + + private function createDocument(): void + { + $this->document = new DOMDocument('1.0', 'UTF-8'); + $this->document->formatOutput = true; + + $this->root = $this->document->createElement('testsuites'); + $this->document->appendChild($this->root); + } + + /** + * @throws InvalidArgumentException + */ + private function handleFault(Errored|Failed $event, string $type): void + { + if (!$this->prepared) { + $this->createTestCase($event); + } + + assert($this->currentTestCase !== null); + + $buffer = $this->testAsString($event->test()); + + $throwable = $event->throwable(); + $buffer .= trim( + $throwable->description() . PHP_EOL . + $throwable->stackTrace(), + ); + + $fault = $this->document->createElement( + $type, + Xml::prepareString($buffer), + ); + + $fault->setAttribute('type', $throwable->className()); + + $this->currentTestCase->appendChild($fault); + + if (!$this->prepared) { + $this->handleFinish($event->telemetryInfo(), 0); + } + } + + /** + * @throws InvalidArgumentException + */ + private function handleIncompleteOrSkipped(MarkedIncomplete|Skipped $event): void + { + if (!$this->prepared) { + $this->createTestCase($event); + } + + assert($this->currentTestCase !== null); + + $skipped = $this->document->createElement('skipped'); + + $this->currentTestCase->appendChild($skipped); + + $this->testSuiteSkipped[$this->testSuiteLevel]++; + + if (!$this->prepared) { + $this->handleFinish($event->telemetryInfo(), 0); + } + } + + /** + * @throws InvalidArgumentException + */ + private function testAsString(Test $test): string + { + if ($test->isPhpt()) { + return basename($test->file()); + } + + assert($test instanceof TestMethod); + + return sprintf( + '%s::%s%s', + $test->className(), + $this->name($test), + PHP_EOL, + ); + } + + /** + * @throws InvalidArgumentException + */ + private function name(Test $test): string + { + if ($test->isPhpt()) { + return basename($test->file()); + } + + assert($test instanceof TestMethod); + + if (!$test->testData()->hasDataFromDataProvider()) { + return $test->methodName(); + } + + $dataSetName = $test->testData()->dataFromDataProvider()->dataSetName(); + + if (is_int($dataSetName)) { + return sprintf( + '%s with data set #%d', + $test->methodName(), + $dataSetName, + ); + } + + return sprintf( + '%s with data set "%s"', + $test->methodName(), + $dataSetName, + ); + } + + /** + * @throws InvalidArgumentException + * + * @phpstan-assert !null $this->currentTestCase + */ + private function createTestCase(Errored|Failed|MarkedIncomplete|PreparationStarted|Prepared|Skipped $event): void + { + $testCase = $this->document->createElement('testcase'); + + $test = $event->test(); + + $testCase->setAttribute('name', $this->name($test)); + $testCase->setAttribute('file', $test->file()); + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + $testCase->setAttribute('line', (string) $test->line()); + $testCase->setAttribute('class', $test->className()); + $testCase->setAttribute('classname', str_replace('\\', '.', $test->className())); + } + + $this->currentTestCase = $testCase; + $this->time = $event->telemetryInfo()->time(); + } +} diff --git a/src/Logging/JUnit/Subscriber/Subscriber.php b/src/Logging/JUnit/Subscriber/Subscriber.php new file mode 100644 index 00000000000..b81f30da409 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private JunitXmlLogger $logger; + + public function __construct(JunitXmlLogger $logger) + { + $this->logger = $logger; + } + + protected function logger(): JunitXmlLogger + { + return $this->logger; + } +} diff --git a/src/Logging/JUnit/Subscriber/TestErroredSubscriber.php b/src/Logging/JUnit/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..114b1c84d24 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestFailedSubscriber.php b/src/Logging/JUnit/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..e8050784329 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestFinishedSubscriber.php b/src/Logging/JUnit/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..55aed8c6614 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php b/src/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..8732af9dd4b --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->testMarkedIncomplete($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php b/src/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php new file mode 100644 index 00000000000..c6fb388f885 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestPreparationErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationErroredSubscriber extends Subscriber implements PreparationErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationErrored $event): void + { + $this->logger()->testPreparationErrored(); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php b/src/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php new file mode 100644 index 00000000000..456466a189f --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestPreparationFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\PreparationFailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationFailedSubscriber extends Subscriber implements PreparationFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationFailed $event): void + { + $this->logger()->testPreparationFailed(); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php b/src/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php new file mode 100644 index 00000000000..8d24d65546a --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestPreparationStartedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationStarted; +use PHPUnit\Event\Test\PreparationStartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationStartedSubscriber extends Subscriber implements PreparationStartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationStarted $event): void + { + $this->logger()->testPreparationStarted($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestPreparedSubscriber.php b/src/Logging/JUnit/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..2a80b8af55d --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared(); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.php b/src/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.php new file mode 100644 index 00000000000..186bf1502e4 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestPrintedUnexpectedOutputSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPrintedUnexpectedOutputSubscriber extends Subscriber implements PrintedUnexpectedOutputSubscriber +{ + public function notify(PrintedUnexpectedOutput $event): void + { + $this->logger()->testPrintedUnexpectedOutput($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.php b/src/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..00617621aba --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestRunnerExecutionFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionFinishedSubscriber extends Subscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + $this->logger()->flush(); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestSkippedSubscriber.php b/src/Logging/JUnit/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..c6ee84ac69e --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php b/src/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php new file mode 100644 index 00000000000..47691770731 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestSuiteFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished(); + } +} diff --git a/src/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php b/src/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php new file mode 100644 index 00000000000..30e350d3419 --- /dev/null +++ b/src/Logging/JUnit/Subscriber/TestSuiteStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\JUnit; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} diff --git a/src/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.php b/src/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.php new file mode 100644 index 00000000000..a8ad7eba5f8 --- /dev/null +++ b/src/Logging/OpenTestReporting/Exception/CannotOpenUriForWritingException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use RuntimeException; + +final class CannotOpenUriForWritingException extends RuntimeException implements Exception +{ +} diff --git a/src/Logging/OpenTestReporting/Exception/Exception.php b/src/Logging/OpenTestReporting/Exception/Exception.php new file mode 100644 index 00000000000..30766ae9f15 --- /dev/null +++ b/src/Logging/OpenTestReporting/Exception/Exception.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +interface Exception extends \PHPUnit\Exception +{ +} diff --git a/src/Logging/OpenTestReporting/InfrastructureInformationProvider.php b/src/Logging/OpenTestReporting/InfrastructureInformationProvider.php new file mode 100644 index 00000000000..c02b6c26740 --- /dev/null +++ b/src/Logging/OpenTestReporting/InfrastructureInformationProvider.php @@ -0,0 +1,186 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function assert; +use function explode; +use function fclose; +use function function_exists; +use function getenv; +use function gethostname; +use function is_resource; +use function php_uname; +use function posix_geteuid; +use function posix_getpwuid; +use function preg_split; +use function proc_close; +use function proc_open; +use function str_contains; +use function str_replace; +use function str_starts_with; +use function stream_get_contents; +use function trim; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class InfrastructureInformationProvider +{ + /** + * @return non-empty-string + */ + public function operatingSystem(): string + { + return php_uname(); + } + + /** + * @return non-empty-string + */ + public function hostName(): string + { + $candidate = gethostname(); + + if ($candidate === false) { + return 'unknown'; + } + + $candidate = trim($candidate); + + if ($candidate === '') { + return 'unknown'; + } + + return $candidate; + } + + /** + * @return non-empty-string + */ + public function userName(): string + { + if (function_exists('posix_getpwuid') && function_exists('posix_geteuid')) { + $candidate = trim(posix_getpwuid(posix_geteuid())['name']); + } elseif (PHP_OS_FAMILY === 'Windows') { + $candidate = trim((string) getenv('USERNAME')); + } + + if (!isset($candidate) || $candidate === '') { + return 'unknown'; + } + + return $candidate; + } + + /** + * @return array{originUrl: non-empty-string, branch: non-empty-string, commit: non-empty-string, clean: bool, status: string}|false + */ + public function gitInformation(): array|false + { + $buffer = $this->executeGitCommand('remote show -n'); + + if ($buffer === false) { + return false; + } + + if (!str_contains($buffer, 'origin')) { + return false; + } + + $buffer = $this->executeGitCommand('remote show -n origin'); + + if ($buffer === false) { + return false; + } + + $lines = preg_split("/\r\n|\n|\r/", $buffer); + + if (!isset($lines[1]) || !str_starts_with($lines[1], ' Fetch URL: ')) { + return false; + } + + $originUrl = trim(str_replace(' Fetch URL: ', '', $lines[1])); + + if (str_contains($originUrl, '@')) { + $originUrl = explode('@', $originUrl)[1]; + } + + $branch = $this->executeGitCommand('symbolic-ref --short HEAD'); + + if ($branch === false) { + return false; + } + + $commit = $this->executeGitCommand('rev-parse HEAD'); + + if ($commit === false) { + return false; + } + + $status = $this->executeGitCommand('status --porcelain'); + + if ($status === false) { + return false; + } + + return [ + 'originUrl' => $originUrl, + 'branch' => $branch, + 'commit' => $commit, + 'clean' => $status === '', + 'status' => $status, + ]; + } + + /** + * @return false|non-empty-string + */ + private function executeGitCommand(string $command): false|string + { + $command = 'git ' . $command; + + if (DIRECTORY_SEPARATOR === '/') { + $command = 'LC_ALL=en_US.UTF-8 ' . $command; + } + + $process = @proc_open( + $command, + [ + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ], + $pipes, + ); + + if (!is_resource($process)) { + return false; + } + + assert(isset($pipes[1]) && is_resource($pipes[1])); + assert(isset($pipes[2]) && is_resource($pipes[2])); + + $result = trim((string) stream_get_contents($pipes[1])); + + fclose($pipes[1]); + fclose($pipes[2]); + + $returnCode = proc_close($process); + + if ($returnCode !== 0) { + return false; + } + + return $result; + } +} diff --git a/src/Logging/OpenTestReporting/OtrXmlLogger.php b/src/Logging/OpenTestReporting/OtrXmlLogger.php new file mode 100644 index 00000000000..7fbe9551e66 --- /dev/null +++ b/src/Logging/OpenTestReporting/OtrXmlLogger.php @@ -0,0 +1,472 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use const PHP_VERSION; +use const ZEND_THREAD_SAFE; +use function array_pop; +use function assert; +use function count; +use function error_get_last; +use function str_replace; +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\Prepared as TestStarted; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use XMLWriter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class OtrXmlLogger +{ + private readonly XMLWriter $writer; + + /** + * @var non-negative-int + */ + private int $idSequence = 0; + + /** + * @var ?positive-int + */ + private ?int $parentId = null; + + /** + * @var list + */ + private array $parentIdStack = []; + + /** + * @var ?positive-int + */ + private ?int $testId = null; + private ?Throwable $parentErrored = null; + private ?Throwable $parentFailed = null; + private bool $alreadyFinished = false; + private bool $includeGitInformation; + + /** + * @param non-empty-string $uri + * + * @throws CannotOpenUriForWritingException + */ + public function __construct(Facade $facade, string $uri, bool $includeGitInformation) + { + $this->writer = new XMLWriter; + + if (@$this->writer->openUri($uri) === false) { + throw new CannotOpenUriForWritingException( + str_replace('XMLWriter::openUri(): ', '', error_get_last()['message']), + ); + } + + $this->writer->setIndent(true); + + $this->registerSubscribers($facade); + + $this->includeGitInformation = $includeGitInformation; + } + + public function testRunnerStarted(): void + { + $infrastructure = new InfrastructureInformationProvider; + $gitInformation = false; + + if ($this->includeGitInformation) { + $gitInformation = $infrastructure->gitInformation(); + } + + $this->writer->startDocument(); + + $this->writer->startElement('e:events'); + $this->writer->writeAttribute('xmlns', 'https://schemas.opentest4j.org/reporting/core/0.2.0'); + $this->writer->writeAttribute('xmlns:e', 'https://schemas.opentest4j.org/reporting/events/0.2.0'); + + if ($gitInformation !== false) { + $this->writer->writeAttribute('xmlns:git', 'https://schemas.opentest4j.org/reporting/git/0.2.0'); + } + + $this->writer->writeAttribute('xmlns:php', 'https://schema.phpunit.de/otr/php/0.0.1'); + $this->writer->writeAttribute('xmlns:phpunit', 'https://schema.phpunit.de/otr/phpunit/0.0.1'); + + $this->writer->startElement('infrastructure'); + $this->writer->writeElement('hostName', $infrastructure->hostName()); + $this->writer->writeElement('userName', $infrastructure->userName()); + $this->writer->writeElement('operatingSystem', $infrastructure->operatingSystem()); + + $this->writer->writeElement('php:phpVersion', PHP_VERSION); + $this->writer->writeElement('php:threadModel', ZEND_THREAD_SAFE ? 'ZTS' : 'NTS'); + + if ($gitInformation !== false) { + $this->writer->startElement('git:repository'); + $this->writer->writeAttribute('originUrl', $gitInformation['originUrl']); + $this->writer->endElement(); + + $this->writer->writeElement('git:branch', $gitInformation['branch']); + $this->writer->writeElement('git:commit', $gitInformation['commit']); + + $this->writer->startElement('git:status'); + $this->writer->writeAttribute('clean', $gitInformation['clean'] === true ? 'true' : 'false'); + $this->writer->writeCdata($gitInformation['status']); + $this->writer->endElement(); + } + + $this->writer->endElement(); + + $this->writer->flush(); + } + + public function testRunnerFinished(): void + { + $this->writer->endDocument(); + + $this->writer->flush(); + } + + public function testSuiteStarted(TestSuiteStarted $event): void + { + $id = $this->nextId(); + + $this->writer->startElement('e:started'); + $this->writer->writeAttribute('id', (string) $id); + + if ($this->parentId !== null) { + $this->writer->writeAttribute('parentId', (string) $this->parentId); + } + + $testSuite = $event->testSuite(); + + $this->writer->writeAttribute('name', $testSuite->name()); + $this->writer->writeAttribute('time', $this->timestamp()); + + if ($testSuite->isForTestClass()) { + assert($testSuite instanceof TestSuiteForTestClass); + + $this->writer->startElement('sources'); + + $this->writer->startElement('fileSource'); + $this->writer->writeAttribute('path', $testSuite->file()); + $this->writer->startElement('filePosition'); + $this->writer->writeAttribute('line', (string) $testSuite->line()); + $this->writer->endElement(); + $this->writer->endElement(); + + $this->writer->startElement('phpunit:classSource'); + $this->writer->writeAttribute('className', $testSuite->className()); + $this->writer->endElement(); + + $this->writer->endElement(); + } + + $this->writer->endElement(); + + $this->writer->flush(); + + $this->parentId = $id; + $this->parentIdStack[] = $id; + } + + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->parentId); + $this->writer->writeAttribute('time', $this->timestamp()); + + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'SKIPPED'); + $this->writer->writeElement('reason', $event->message()); + $this->writer->endElement(); + + $this->writer->endElement(); + + $this->writer->flush(); + + $this->reduceTestSuiteLevel(); + } + + public function testSuiteFinished(): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->parentId); + $this->writer->writeAttribute('time', $this->timestamp()); + + if ($this->parentErrored !== null) { + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'ERRORED'); + $this->writer->writeElement('reason', $this->parentErrored->message()); + $this->writeThrowable($this->parentErrored, false); + $this->writer->endElement(); + } elseif ($this->parentFailed !== null) { + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', 'FAILED'); + $this->writer->writeElement('reason', $this->parentFailed->message()); + $this->writeThrowable($this->parentFailed, true); + $this->writer->endElement(); + } + + $this->writer->endElement(); + + $this->writer->flush(); + + $this->parentErrored = null; + $this->parentFailed = null; + + $this->reduceTestSuiteLevel(); + } + + public function testPrepared(PreparationErrored|PreparationFailed|TestStarted $event): void + { + $this->testId = $this->nextId(); + + $this->writeTestStarted( + $event->test(), + $this->testId, + $this->parentId, + ); + } + + public function testFinished(): void + { + if (!$this->alreadyFinished) { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', Status::Successful->value); + $this->writer->endElement(); + $this->writer->endElement(); + } + + $this->alreadyFinished = false; + $this->testId = null; + } + + public function testFailed(Failed $event): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', Status::Failed->value); + + $this->writer->writeElement('reason', $event->throwable()->message()); + $this->writeThrowable($event->throwable(), true); + + $this->writer->endElement(); + $this->writer->endElement(); + + $this->writer->flush(); + + $this->alreadyFinished = true; + } + + public function testErrored(Errored $event): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', Status::Errored->value); + + $this->writer->writeElement('reason', $event->throwable()->message()); + $this->writeThrowable($event->throwable(), false); + + $this->writer->endElement(); + $this->writer->endElement(); + + $this->writer->flush(); + + $this->alreadyFinished = true; + } + + public function testSkipped(Skipped $event): void + { + if ($this->testId === null) { + $this->testId = $this->nextId(); + + $this->writeTestStarted( + $event->test(), + $this->testId, + $this->parentId, + ); + } + + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', Status::Skipped->value); + + $this->writer->writeElement('reason', $event->message()); + + $this->writer->endElement(); + $this->writer->endElement(); + + $this->writer->flush(); + + $this->alreadyFinished = true; + } + + public function markTestIncomplete(MarkedIncomplete $event): void + { + $this->writer->startElement('e:finished'); + $this->writer->writeAttribute('id', (string) $this->testId); + $this->writer->writeAttribute('time', $this->timestamp()); + $this->writer->startElement('result'); + $this->writer->writeAttribute('status', Status::Aborted->value); + + $this->writer->writeElement('reason', $event->throwable()->message()); + $this->writeThrowable($event->throwable(), false); + + $this->writer->endElement(); + $this->writer->endElement(); + + $this->writer->flush(); + + $this->alreadyFinished = true; + } + + public function parentErrored(AfterLastTestMethodErrored|BeforeFirstTestMethodErrored $event): void + { + $this->parentErrored = $event->throwable(); + } + + public function parentFailed(AfterLastTestMethodFailed|BeforeFirstTestMethodFailed $event): void + { + $this->parentFailed = $event->throwable(); + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new TestRunnerStartedSubscriber($this), + new TestSuiteStartedSubscriber($this), + new TestSuiteSkippedSubscriber($this), + new BeforeFirstTestMethodErroredSubscriber($this), + new BeforeFirstTestMethodFailedSubscriber($this), + new AfterLastTestMethodErroredSubscriber($this), + new AfterLastTestMethodFailedSubscriber($this), + new TestPreparationErroredSubscriber($this), + new TestPreparationFailedSubscriber($this), + new TestPreparedSubscriber($this), + new TestAbortedSubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestSkippedSubscriber($this), + new TestFinishedSubscriber($this), + new TestSuiteFinishedSubscriber($this), + new TestRunnerFinishedSubscriber($this), + ); + } + + /** + * @param positive-int $id + * @param ?positive-int $parentId + */ + private function writeTestStarted(Test $test, int $id, ?int $parentId): void + { + $this->writer->startElement('e:started'); + $this->writer->writeAttribute('id', (string) $id); + + if ($parentId !== null) { + $this->writer->writeAttribute('parentId', (string) $parentId); + } + + $this->writer->writeAttribute('name', $test->name()); + $this->writer->writeAttribute('time', $this->timestamp()); + + $this->writer->startElement('sources'); + + $this->writer->startElement('fileSource'); + $this->writer->writeAttribute('path', $test->file()); + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + $this->writer->startElement('filePosition'); + $this->writer->writeAttribute('line', (string) $test->line()); + $this->writer->endElement(); + } + + $this->writer->endElement(); + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + $this->writer->startElement('phpunit:methodSource'); + $this->writer->writeAttribute('className', $test->className()); + $this->writer->writeAttribute('methodName', $test->methodName()); + $this->writer->endElement(); + } + + $this->writer->endElement(); + + $this->writer->endElement(); + + $this->writer->flush(); + } + + private function writeThrowable(Throwable $throwable, bool $assertionError): void + { + $this->writer->startElement('phpunit:throwable'); + $this->writer->writeAttribute('type', $throwable->className()); + $this->writer->writeAttribute('assertionError', $assertionError ? 'true' : 'false'); + $this->writer->writeCdata($throwable->asString()); + $this->writer->endElement(); + } + + /** + * @return non-empty-string + */ + private function timestamp(): string + { + return new DateTimeImmutable('now', new DateTimeZone('UTC'))->format('Y-m-d\TH:i:s.u\Z'); + } + + /** + * @return positive-int + */ + private function nextId(): int + { + return ++$this->idSequence; + } + + private function reduceTestSuiteLevel(): void + { + array_pop($this->parentIdStack); + + if ($this->parentIdStack !== []) { + $this->parentId = $this->parentIdStack[count($this->parentIdStack) - 1]; + + return; + } + + $this->parentId = null; + } +} diff --git a/src/Logging/OpenTestReporting/Status.php b/src/Logging/OpenTestReporting/Status.php new file mode 100644 index 00000000000..4ff399b2cfc --- /dev/null +++ b/src/Logging/OpenTestReporting/Status.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This enumeration is not covered by the backward compatibility promise for PHPUnit + */ +enum Status: string +{ + case Aborted = 'ABORTED'; + case Errored = 'ERRORED'; + case Failed = 'FAILED'; + case Skipped = 'SKIPPED'; + case Successful = 'SUCCESSFUL'; +} diff --git a/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..5b31f11cfc5 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodErroredSubscriber as AfterLastTestMethodErroredSubscriberInterface; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodErroredSubscriber extends Subscriber implements AfterLastTestMethodErroredSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(AfterLastTestMethodErrored $event): void + { + $this->logger()->parentErrored($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..340d26d737e --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/AfterLastTestMethodFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\AfterLastTestMethodFailedSubscriber as AfterLastTestMethodFailedSubscriberInterface; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterLastTestMethodFailedSubscriber extends Subscriber implements AfterLastTestMethodFailedSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(AfterLastTestMethodFailed $event): void + { + $this->logger()->parentFailed($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..3fb8c1efc7d --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber as BeforeFirstTestMethodErroredSubscriberInterface; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodErroredSubscriber extends Subscriber implements BeforeFirstTestMethodErroredSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->logger()->parentErrored($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php new file mode 100644 index 00000000000..fad858cfe89 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/BeforeFirstTestMethodFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber as BeforeFirstTestMethodFailedSubscriberInterface; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeFirstTestMethodFailedSubscriber extends Subscriber implements BeforeFirstTestMethodFailedSubscriberInterface +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodFailed $event): void + { + $this->logger()->parentFailed($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/Subscriber.php b/src/Logging/OpenTestReporting/Subscriber/Subscriber.php new file mode 100644 index 00000000000..84b71de679c --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private OtrXmlLogger $logger; + + public function __construct(OtrXmlLogger $logger) + { + $this->logger = $logger; + } + + protected function logger(): OtrXmlLogger + { + return $this->logger; + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.php new file mode 100644 index 00000000000..31376214a0b --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestAbortedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestAbortedSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->markTestIncomplete($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..1a8a40be927 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..0b0caf97175 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..d05de8b5ac2 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished(); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.php new file mode 100644 index 00000000000..6fb72562863 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestPreparationErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationErrored; +use PHPUnit\Event\Test\PreparationErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationErroredSubscriber extends Subscriber implements PreparationErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationErrored $event): void + { + $this->logger()->testPrepared($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.php new file mode 100644 index 00000000000..f0167508aba --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestPreparationFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\PreparationFailed; +use PHPUnit\Event\Test\PreparationFailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparationFailedSubscriber extends Subscriber implements PreparationFailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(PreparationFailed $event): void + { + $this->logger()->testPrepared($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..9138f142b8a --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.php new file mode 100644 index 00000000000..d690ba567c2 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestRunnerFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerFinishedSubscriber extends Subscriber implements ExecutionFinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(ExecutionFinished $event): void + { + $this->logger()->testRunnerFinished(); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php new file mode 100644 index 00000000000..6aba01c9646 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestRunnerStartedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\Application\Started; +use PHPUnit\Event\Application\StartedSubscriber; +use PHPUnit\Event\InvalidArgumentException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerStartedSubscriber extends Subscriber implements StartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Started $event): void + { + $this->logger()->testRunnerStarted(); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..32e67ca8cf1 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php new file mode 100644 index 00000000000..16ebf626ced --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestSuiteFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished(); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php new file mode 100644 index 00000000000..58691b613af --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestSuiteSkippedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSuiteSkipped($event); + } +} diff --git a/src/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php b/src/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php new file mode 100644 index 00000000000..78678012520 --- /dev/null +++ b/src/Logging/OpenTestReporting/Subscriber/TestSuiteStartedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\OpenTestReporting; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} diff --git a/src/Logging/OpenTestReporting/schema/core-0.2.0.xsd b/src/Logging/OpenTestReporting/schema/core-0.2.0.xsd new file mode 100644 index 00000000000..170e20cae52 --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/core-0.2.0.xsd @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The media type of the file content, e.g. 'text/plain' or 'application/json', + see https://www.iana.org/assignments/media-types/media-types.xhtml. + For text files, the charset should be specified in the 'charset' attribute, + e.g. 'text/plain; charset=utf-8'. + + + + + + + + + + + + + + Typically 'stdout' or 'stderr' but may also be used for attaching other log output + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Logging/OpenTestReporting/schema/events-0.2.0.xsd b/src/Logging/OpenTestReporting/schema/events-0.2.0.xsd new file mode 100644 index 00000000000..e5c37ccc3e2 --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/events-0.2.0.xsd @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Logging/OpenTestReporting/schema/git-0.2.0.xsd b/src/Logging/OpenTestReporting/schema/git-0.2.0.xsd new file mode 100644 index 00000000000..1a1dd6d6a08 --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/git-0.2.0.xsd @@ -0,0 +1,69 @@ + + + + + + + + + the URL of the 'origin' remote of the Git repository + + + + + + + + + + + + + + + + + + + + the branch the HEAD commit is pointing to, if any + + + + + + + + + + + + the commit hash + + + + + + + + + + + + the output of `git status --porcelain`, potentially empty + + + + + whether the working directory clean contains no changes or untracked files + + + + + + + + + diff --git a/src/Logging/OpenTestReporting/schema/otr.xsd b/src/Logging/OpenTestReporting/schema/otr.xsd new file mode 100644 index 00000000000..982dac4dede --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/otr.xsd @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/Logging/OpenTestReporting/schema/php.xsd b/src/Logging/OpenTestReporting/schema/php.xsd new file mode 100644 index 00000000000..f880345d108 --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/php.xsd @@ -0,0 +1,15 @@ + + + + + + + + + + + + + diff --git a/src/Logging/OpenTestReporting/schema/phpunit.xsd b/src/Logging/OpenTestReporting/schema/phpunit.xsd new file mode 100644 index 00000000000..0a0c00edaab --- /dev/null +++ b/src/Logging/OpenTestReporting/schema/phpunit.xsd @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Logging/TeamCity/Subscriber/Subscriber.php b/src/Logging/TeamCity/Subscriber/Subscriber.php new file mode 100644 index 00000000000..b1ad46d833d --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private TeamCityLogger $logger; + + public function __construct(TeamCityLogger $logger) + { + $this->logger = $logger; + } + + protected function logger(): TeamCityLogger + { + return $this->logger; + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php b/src/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php new file mode 100644 index 00000000000..9482ccb22d1 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestConsideredRiskySubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(ConsideredRisky $event): void + { + $this->logger()->testConsideredRisky($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestErroredSubscriber.php b/src/Logging/TeamCity/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..4ce8d0cb774 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Errored $event): void + { + $this->logger()->testErrored($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestFailedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..8d8caa6308e --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Failed $event): void + { + $this->logger()->testFailed($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..6b4bef3dcc1 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->logger()->testFinished($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php b/src/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..b38d54c44a2 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(MarkedIncomplete $event): void + { + $this->logger()->testMarkedIncomplete($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..85476a059d4 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->logger()->testPrepared($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..824ea424438 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestRunnerExecutionFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionFinishedSubscriber extends Subscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + $this->logger()->flush(); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestSkippedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..0f55795fc5a --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSkipped($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php b/src/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php new file mode 100644 index 00000000000..25459197b96 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestSuiteBeforeFirstTestMethodErroredSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBeforeFirstTestMethodErroredSubscriber extends Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->logger()->beforeFirstTestMethodErrored($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php new file mode 100644 index 00000000000..71889d8ce65 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestSuiteFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->logger()->testSuiteFinished($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php new file mode 100644 index 00000000000..2d6a3f3d248 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestSuiteSkippedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->logger()->testSuiteSkipped($event); + } +} diff --git a/src/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php b/src/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php new file mode 100644 index 00000000000..7caba60b6a5 --- /dev/null +++ b/src/Logging/TeamCity/Subscriber/TestSuiteStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->logger()->testSuiteStarted($event); + } +} diff --git a/src/Logging/TeamCity/TeamCityLogger.php b/src/Logging/TeamCity/TeamCityLogger.php new file mode 100644 index 00000000000..9a56fc3832d --- /dev/null +++ b/src/Logging/TeamCity/TeamCityLogger.php @@ -0,0 +1,418 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TeamCity; + +use function assert; +use function getmypid; +use function ini_get; +use function is_a; +use function round; +use function sprintf; +use function str_replace; +use function stripos; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Event; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; +use PHPUnit\Framework\Exception as FrameworkException; +use PHPUnit\TextUI\Output\Printer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TeamCityLogger +{ + private readonly Printer $printer; + private bool $isSummaryTestCountPrinted = false; + private ?HRTime $time = null; + private ?int $flowId = null; + + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + + $this->registerSubscribers($facade); + $this->setFlowId(); + } + + public function testSuiteStarted(TestSuiteStarted $event): void + { + $testSuite = $event->testSuite(); + + if (!$this->isSummaryTestCountPrinted) { + $this->isSummaryTestCountPrinted = true; + + $this->writeMessage( + 'testCount', + ['count' => $testSuite->count()], + ); + } + + $parameters = ['name' => $testSuite->name()]; + + if ($testSuite->isForTestClass()) { + assert($testSuite instanceof TestSuiteForTestClass); + + $parameters['locationHint'] = sprintf( + 'php_qn://%s::\\%s', + $testSuite->file(), + $testSuite->name(), + ); + } elseif ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + + $parameters['locationHint'] = sprintf( + 'php_qn://%s::\\%s', + $testSuite->file(), + $testSuite->name(), + ); + + $parameters['name'] = $testSuite->methodName(); + } + + $this->writeMessage('testSuiteStarted', $parameters); + } + + public function testSuiteFinished(TestSuiteFinished $event): void + { + $testSuite = $event->testSuite(); + + $parameters = ['name' => $testSuite->name()]; + + if ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + + $parameters['name'] = $testSuite->methodName(); + } + + $this->writeMessage('testSuiteFinished', $parameters); + } + + public function testPrepared(Prepared $event): void + { + $test = $event->test(); + + $parameters = [ + 'name' => $test->name(), + ]; + + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + $parameters['locationHint'] = sprintf( + 'php_qn://%s::\\%s::%s', + $test->file(), + $test->className(), + $test->name(), + ); + } + + $this->writeMessage('testStarted', $parameters); + + $this->time = $event->telemetryInfo()->time(); + } + + /** + * @throws InvalidArgumentException + */ + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + + $this->writeMessage( + 'testIgnored', + [ + 'name' => $event->test()->name(), + 'message' => $event->throwable()->message(), + 'details' => $this->details($event->throwable()), + 'duration' => $this->duration($event), + ], + ); + } + + /** + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + + $parameters = [ + 'name' => $event->test()->name(), + 'message' => $event->message(), + ]; + + $parameters['duration'] = $this->duration($event); + + $this->writeMessage('testIgnored', $parameters); + } + + /** + * @throws InvalidArgumentException + */ + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + + $parameters = [ + 'name' => $event->testSuite()->name(), + 'message' => $event->message(), + ]; + + $parameters['duration'] = $this->duration($event); + + $this->writeMessage('testIgnored', $parameters); + $this->writeMessage('testSuiteFinished', $parameters); + } + + /** + * @throws InvalidArgumentException + */ + public function beforeFirstTestMethodErrored(BeforeFirstTestMethodErrored $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + + $parameters = [ + 'name' => $event->testClassName(), + 'message' => $this->message($event->throwable()), + 'details' => $this->details($event->throwable()), + 'duration' => $this->duration($event), + ]; + + $this->writeMessage('testFailed', $parameters); + $this->writeMessage('testSuiteFinished', $parameters); + } + + /** + * @throws InvalidArgumentException + */ + public function testErrored(Errored $event): void + { + if ($this->time === null) { + $this->time = $event->telemetryInfo()->time(); + } + + $this->writeMessage( + 'testFailed', + [ + 'name' => $event->test()->name(), + 'message' => $this->message($event->throwable()), + 'details' => $this->details($event->throwable()), + 'duration' => $this->duration($event), + ], + ); + } + + /** + * @throws InvalidArgumentException + */ + public function testFailed(Failed $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + + $parameters = [ + 'name' => $event->test()->name(), + 'message' => $this->message($event->throwable()), + 'details' => $this->details($event->throwable()), + 'duration' => $this->duration($event), + ]; + + if ($event->hasComparisonFailure()) { + $parameters['type'] = 'comparisonFailure'; + $parameters['actual'] = $event->comparisonFailure()->actual(); + $parameters['expected'] = $event->comparisonFailure()->expected(); + } + + $this->writeMessage('testFailed', $parameters); + } + + /** + * @throws InvalidArgumentException + */ + public function testConsideredRisky(ConsideredRisky $event): void + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + $this->time = $event->telemetryInfo()->time(); + // @codeCoverageIgnoreEnd + } + + $this->writeMessage( + 'testFailed', + [ + 'name' => $event->test()->name(), + 'message' => $event->message(), + 'details' => '', + 'duration' => $this->duration($event), + ], + ); + } + + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + $this->writeMessage( + 'testFinished', + [ + 'name' => $event->test()->name(), + 'duration' => $this->duration($event), + ], + ); + + $this->time = null; + } + + public function flush(): void + { + $this->printer->flush(); + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new TestSuiteStartedSubscriber($this), + new TestSuiteFinishedSubscriber($this), + new TestPreparedSubscriber($this), + new TestFinishedSubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestSkippedSubscriber($this), + new TestSuiteSkippedSubscriber($this), + new TestConsideredRiskySubscriber($this), + new TestRunnerExecutionFinishedSubscriber($this), + new TestSuiteBeforeFirstTestMethodErroredSubscriber($this), + ); + } + + private function setFlowId(): void + { + if (stripos(ini_get('disable_functions'), 'getmypid') === false) { + $this->flowId = getmypid(); + } + } + + /** + * @param array $parameters + */ + private function writeMessage(string $eventName, array $parameters = []): void + { + $this->printer->print( + sprintf( + '##teamcity[%s', + $eventName, + ), + ); + + if ($this->flowId !== null) { + $parameters['flowId'] = $this->flowId; + } + + foreach ($parameters as $key => $value) { + $this->printer->print( + sprintf( + " %s='%s'", + $key, + $this->escape((string) $value), + ), + ); + } + + $this->printer->print("]\n"); + } + + /** + * @throws InvalidArgumentException + */ + private function duration(Event $event): int + { + if ($this->time === null) { + // @codeCoverageIgnoreStart + return 0; + // @codeCoverageIgnoreEnd + } + + return (int) round($event->telemetryInfo()->time()->duration($this->time)->asFloat() * 1000); + } + + private function escape(string $string): string + { + return str_replace( + ['|', "'", "\n", "\r", ']', '['], + ['||', "|'", '|n', '|r', '|]', '|['], + $string, + ); + } + + private function message(Throwable $throwable): string + { + if (is_a($throwable->className(), FrameworkException::class, true)) { + return $throwable->message(); + } + + $buffer = $throwable->className(); + + if ($throwable->message() !== '') { + $buffer .= ': ' . $throwable->message(); + } + + return $buffer; + } + + private function details(Throwable $throwable): string + { + $buffer = $throwable->stackTrace(); + + while ($throwable->hasPrevious()) { + $throwable = $throwable->previous(); + + $buffer .= sprintf( + "\nCaused by\n%s\n%s", + $throwable->description(), + $throwable->stackTrace(), + ); + } + + return $buffer; + } +} diff --git a/src/Logging/TestDox/HtmlRenderer.php b/src/Logging/TestDox/HtmlRenderer.php new file mode 100644 index 00000000000..3d74d593616 --- /dev/null +++ b/src/Logging/TestDox/HtmlRenderer.php @@ -0,0 +1,143 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HtmlRenderer +{ + private const string PAGE_HEADER = <<<'EOT' + + + + + Test Documentation + + + +EOT; + private const string CLASS_HEADER = <<<'EOT' + +

%s

+
    + +EOT; + private const string CLASS_FOOTER = <<<'EOT' +
+EOT; + private const string PAGE_FOOTER = <<<'EOT' + + + +EOT; + + /** + * @param array $tests + */ + public function render(array $tests): string + { + $buffer = self::PAGE_HEADER; + + foreach ($tests as $prettifiedClassName => $_tests) { + $buffer .= sprintf( + self::CLASS_HEADER, + $prettifiedClassName, + ); + + foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { + $buffer .= sprintf( + "
  • %s
  • \n", + $outcome, + $prettifiedMethodName, + ); + } + + $buffer .= self::CLASS_FOOTER; + } + + return $buffer . self::PAGE_FOOTER; + } + + /** + * @return array + */ + private function reduce(TestResultCollection $tests): array + { + $result = []; + + foreach ($tests as $test) { + $prettifiedMethodName = $test->test()->testDox()->prettifiedMethodName(); + + if (!isset($result[$prettifiedMethodName])) { + $result[$prettifiedMethodName] = $test->status()->isSuccess() ? 'success' : 'defect'; + + continue; + } + + if ($test->status()->isSuccess()) { + continue; + } + + $result[$prettifiedMethodName] = 'defect'; + } + + return $result; + } +} diff --git a/src/Logging/TestDox/NamePrettifier.php b/src/Logging/TestDox/NamePrettifier.php new file mode 100644 index 00000000000..99d266c6c01 --- /dev/null +++ b/src/Logging/TestDox/NamePrettifier.php @@ -0,0 +1,441 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use const PHP_EOL; +use function array_key_exists; +use function array_keys; +use function array_map; +use function array_pop; +use function array_values; +use function assert; +use function class_exists; +use function explode; +use function gettype; +use function implode; +use function is_bool; +use function is_float; +use function is_int; +use function is_object; +use function is_scalar; +use function method_exists; +use function preg_quote; +use function preg_replace; +use function rtrim; +use function sprintf; +use function str_contains; +use function str_ends_with; +use function str_replace; +use function str_starts_with; +use function strlen; +use function strtolower; +use function strtoupper; +use function substr; +use function trim; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\TestDox; +use PHPUnit\Metadata\TestDoxFormatter; +use PHPUnit\Util\Color; +use PHPUnit\Util\Exporter; +use PHPUnit\Util\Filter; +use ReflectionEnum; +use ReflectionMethod; +use ReflectionObject; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NamePrettifier +{ + /** + * @var array + */ + private array $strings = []; + + /** + * @var array + */ + private array $prettifiedTestCases = []; + + /** + * @var array + */ + private array $erroredFormatters = []; + + /** + * @param class-string $className + */ + public function prettifyTestClassName(string $className): string + { + if (class_exists($className)) { + $classLevelTestDox = MetadataRegistry::parser()->forClass($className)->isTestDox(); + + if ($classLevelTestDox->isNotEmpty()) { + $classLevelTestDox = $classLevelTestDox->asArray()[0]; + + assert($classLevelTestDox instanceof TestDox); + + return $classLevelTestDox->text(); + } + } + + $parts = explode('\\', $className); + $className = array_pop($parts); + + if (str_ends_with($className, 'Test')) { + $className = substr($className, 0, strlen($className) - strlen('Test')); + } + + if (str_starts_with($className, 'Tests')) { + $className = substr($className, strlen('Tests')); + } elseif (str_starts_with($className, 'Test')) { + $className = substr($className, strlen('Test')); + } + + if ($className === '') { + $className = 'UnnamedTests'; + } + + if ($parts !== []) { + $parts[] = $className; + $fullyQualifiedName = implode('\\', $parts); + } else { + $fullyQualifiedName = $className; + } + + $result = preg_replace('/(?<=[[:lower:]])(?=[[:upper:]])/u', ' ', $className); + + if ($fullyQualifiedName !== $className) { + return $result . ' (' . $fullyQualifiedName . ')'; + } + + return $result; + } + + // NOTE: this method is on a hot path and very performance sensitive. change with care. + public function prettifyTestMethodName(string $name): string + { + if ($name === '') { + return ''; + } + + $string = rtrim($name, '0123456789'); + + if (array_key_exists($string, $this->strings)) { + $name = $string; + } elseif ($string === $name) { + $this->strings[$string] = 1; + } + + if (str_starts_with($name, 'test_')) { + $name = substr($name, 5); + } elseif (str_starts_with($name, 'test')) { + $name = substr($name, 4); + } + + if ($name === '') { + return ''; + } + + $name[0] = strtoupper($name[0]); + + $noUnderscore = str_replace('_', ' ', $name); + + if ($noUnderscore !== $name) { + return trim($noUnderscore); + } + + $wasNumeric = false; + + $buffer = ''; + + $len = strlen($name); + + for ($i = 0; $i < $len; $i++) { + if ($i > 0 && $name[$i] >= 'A' && $name[$i] <= 'Z') { + $buffer .= ' ' . strtolower($name[$i]); + } else { + $isNumeric = $name[$i] >= '0' && $name[$i] <= '9'; + + if (!$wasNumeric && $isNumeric) { + $buffer .= ' '; + $wasNumeric = true; + } + + if ($wasNumeric && !$isNumeric) { + $wasNumeric = false; + } + + $buffer .= $name[$i]; + } + } + + return trim($buffer); + } + + public function prettifyTestCase(TestCase $test, bool $colorize): string + { + $key = $test::class . '#' . $test->name(); + + if ($test->usesDataProvider()) { + $key .= '#' . $test->dataName(); + } + + if ($colorize) { + $key .= '#colorize'; + } + + if (isset($this->prettifiedTestCases[$key])) { + return $this->prettifiedTestCases[$key]; + } + + $metadataCollection = MetadataRegistry::parser()->forMethod($test::class, $test->name()); + $testDox = $metadataCollection->isTestDox()->isMethodLevel(); + $callback = $metadataCollection->isTestDoxFormatter(); + $isCustomized = false; + + if ($testDox->isNotEmpty()) { + $testDox = $testDox->asArray()[0]; + + assert($testDox instanceof TestDox); + + [$result, $isCustomized] = $this->processTestDox($test, $testDox, $colorize); + } elseif ($callback->isNotEmpty()) { + $callback = $callback->asArray()[0]; + + assert($callback instanceof TestDoxFormatter); + + [$result, $isCustomized] = $this->processTestDoxFormatter($test, $callback); + } else { + $result = $this->prettifyTestMethodName($test->name()); + } + + if (!$isCustomized && $test->usesDataProvider()) { + $result .= $this->prettifyDataSet($test, $colorize); + } + + $this->prettifiedTestCases[$key] = $result; + + return $result; + } + + public function prettifyDataSet(TestCase $test, bool $colorize): string + { + if (!$colorize) { + return $test->dataSetAsString(); + } + + if (is_int($test->dataName())) { + return Color::dim(' with data set ') . Color::colorize('fg-cyan', (string) $test->dataName()); + } + + return Color::dim(' with ') . Color::colorize('fg-cyan', Color::visualizeWhitespace($test->dataName())); + } + + /** + * @return array + */ + private function mapTestMethodParameterNamesToProvidedDataValues(TestCase $test, bool $colorize): array + { + assert(method_exists($test, $test->name())); + + /** @noinspection PhpUnhandledExceptionInspection */ + $reflector = new ReflectionMethod($test::class, $test->name()); + + $providedData = []; + $providedDataValues = array_values($test->providedData()); + $i = 0; + + $providedData['$_dataName'] = $test->dataName(); + + foreach ($reflector->getParameters() as $parameter) { + if (!array_key_exists($i, $providedDataValues) && $parameter->isDefaultValueAvailable()) { + $providedDataValues[$i] = $parameter->getDefaultValue(); + } + + $value = $providedDataValues[$i++] ?? null; + + if (is_object($value)) { + $value = $this->objectToString($value); + } + + if (!is_scalar($value)) { + $value = gettype($value); + + if ($value === 'NULL') { + $value = 'null'; + } + } + + if (is_bool($value) || is_int($value) || is_float($value)) { + $value = Exporter::export($value); + } + + if ($value === '') { + if ($colorize) { + $value = Color::colorize('dim,underlined', 'empty'); + } else { + $value = "''"; + } + } + + $providedData['$' . $parameter->getName()] = str_replace('$', '\\$', $value); + } + + if ($colorize) { + $providedData = array_map( + static fn (mixed $value) => Color::colorize('fg-cyan', Color::visualizeWhitespace((string) $value, true)), + $providedData, + ); + } + + return $providedData; + } + + /** + * @return non-empty-string + */ + private function objectToString(object $value): string + { + $reflector = new ReflectionObject($value); + + if ($reflector->isEnum()) { + $enumReflector = new ReflectionEnum($value); + + if ($enumReflector->isBacked()) { + return (string) $value->value; + } + + return $value->name; + } + + if ($reflector->hasMethod('__toString')) { + return $value->__toString(); + } + + return $value::class; + } + + /** + * @return array{0: string, 1: bool} + */ + private function processTestDox(TestCase $test, TestDox $testDox, bool $colorize): array + { + $placeholdersUsed = false; + + $result = $testDox->text(); + + if (str_contains($result, '$')) { + $annotation = $result; + $providedData = $this->mapTestMethodParameterNamesToProvidedDataValues($test, $colorize); + + $variables = array_map( + static fn (string $variable): string => sprintf( + '/%s(?=\b)/', + preg_quote($variable, '/'), + ), + array_keys($providedData), + ); + + $result = preg_replace($variables, $providedData, $annotation); + + $placeholdersUsed = true; + } + + return [$result, $placeholdersUsed]; + } + + /** + * @return array{0: string, 1: bool} + */ + private function processTestDoxFormatter(TestCase $test, TestDoxFormatter $formatter): array + { + $className = $formatter->className(); + $methodName = $formatter->methodName(); + $formatterIdentifier = $className . '::' . $methodName; + + if (isset($this->erroredFormatters[$formatterIdentifier])) { + return [$this->prettifyTestMethodName($test->name()), false]; + } + + if (!method_exists($className, $methodName)) { + EventFacade::emitter()->testTriggeredPhpunitError( + TestMethodBuilder::fromTestCase($test, false), + sprintf( + 'Method %s::%s() cannot be used as a TestDox formatter because it does not exist', + $className, + $methodName, + ), + ); + + $this->erroredFormatters[$formatterIdentifier] = true; + + return [$this->prettifyTestMethodName($test->name()), false]; + } + + $reflector = new ReflectionMethod($className, $methodName); + + if (!$reflector->isPublic()) { + EventFacade::emitter()->testTriggeredPhpunitError( + TestMethodBuilder::fromTestCase($test, false), + sprintf( + 'Method %s::%s() cannot be used as a TestDox formatter because it is not public', + $className, + $methodName, + ), + ); + + $this->erroredFormatters[$formatterIdentifier] = true; + + return [$this->prettifyTestMethodName($test->name()), false]; + } + + if (!$reflector->isStatic()) { + EventFacade::emitter()->testTriggeredPhpunitError( + TestMethodBuilder::fromTestCase($test, false), + sprintf( + 'Method %s::%s() cannot be used as a TestDox formatter because it is not static', + $className, + $methodName, + ), + ); + + $this->erroredFormatters[$formatterIdentifier] = true; + + return [$this->prettifyTestMethodName($test->name()), false]; + } + + try { + return [$reflector->invokeArgs(null, array_values($test->providedData())), true]; + } catch (Throwable $t) { + EventFacade::emitter()->testTriggeredPhpunitError( + TestMethodBuilder::fromTestCase($test, false), + sprintf( + 'TestDox formatter %s::%s() triggered an error: %s%s%s', + $className, + $methodName, + $t->getMessage(), + PHP_EOL, + Filter::stackTraceFromThrowableAsString($t), + ), + ); + + $this->erroredFormatters[$formatterIdentifier] = true; + + return [$this->prettifyTestMethodName($test->name()), false]; + } + } +} diff --git a/src/Logging/TestDox/PlainTextRenderer.php b/src/Logging/TestDox/PlainTextRenderer.php new file mode 100644 index 00000000000..db591ca9fe1 --- /dev/null +++ b/src/Logging/TestDox/PlainTextRenderer.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function sprintf; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PlainTextRenderer +{ + /** + * @param array $tests + */ + public function render(array $tests): string + { + $buffer = ''; + + foreach ($tests as $prettifiedClassName => $_tests) { + $buffer .= $prettifiedClassName . "\n"; + + foreach ($this->reduce($_tests) as $prettifiedMethodName => $outcome) { + $buffer .= sprintf( + ' [%s] %s' . "\n", + $outcome, + $prettifiedMethodName, + ); + } + + $buffer .= "\n"; + } + + return $buffer; + } + + /** + * @return array + */ + private function reduce(TestResultCollection $tests): array + { + $result = []; + + foreach ($tests as $test) { + $prettifiedMethodName = $test->test()->testDox()->prettifiedMethodName(); + + $success = true; + + if ($test->status()->isError() || + $test->status()->isFailure() || + $test->status()->isIncomplete() || + $test->status()->isSkipped()) { + $success = false; + } + + if (!isset($result[$prettifiedMethodName])) { + $result[$prettifiedMethodName] = $success ? 'x' : ' '; + + continue; + } + + if ($success) { + continue; + } + + $result[$prettifiedMethodName] = ' '; + } + + return $result; + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/Subscriber.php b/src/Logging/TestDox/TestResult/Subscriber/Subscriber.php new file mode 100644 index 00000000000..41fc465a120 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private TestResultCollector $collector; + + public function __construct(TestResultCollector $collector) + { + $this->collector = $collector; + } + + protected function collector(): TestResultCollector + { + return $this->collector; + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.php new file mode 100644 index 00000000000..150a486350b --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestConsideredRiskySubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->collector()->testConsideredRisky($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..b210ffa3c32 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->collector()->testErrored($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..b776227c38b --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->collector()->testFailed($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..14ddea33ea9 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->collector()->testFinished($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..7e21545cb10 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->collector()->testMarkedIncomplete($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php new file mode 100644 index 00000000000..1eb1a5777cd --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestPassedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Passed; +use PHPUnit\Event\Test\PassedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPassedSubscriber extends Subscriber implements PassedSubscriber +{ + public function notify(Passed $event): void + { + $this->collector()->testPassed($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..cdaddb09a13 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..76d7e3bb094 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSkipped($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..8e080296632 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php new file mode 100644 index 00000000000..18eff3a9d05 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testTriggeredNotice($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php new file mode 100644 index 00000000000..082bb3c334a --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpDeprecation($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php new file mode 100644 index 00000000000..b743b64a3f8 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpNotice($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php new file mode 100644 index 00000000000..4e9c6ac1aeb --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpWarning($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php new file mode 100644 index 00000000000..4423ff98cfc --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpunitDeprecation($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php new file mode 100644 index 00000000000..e4e90f18d91 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitErrorSubscriber extends Subscriber implements PhpunitErrorTriggeredSubscriber +{ + public function notify(PhpunitErrorTriggered $event): void + { + $this->collector()->testTriggeredPhpunitError($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php new file mode 100644 index 00000000000..72cb8af22c6 --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpunitWarning($event); + } +} diff --git a/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.php b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.php new file mode 100644 index 00000000000..d44f4005c6a --- /dev/null +++ b/src/Logging/TestDox/TestResult/Subscriber/TestTriggeredWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testTriggeredWarning($event); + } +} diff --git a/src/Logging/TestDox/TestResult/TestResult.php b/src/Logging/TestDox/TestResult/TestResult.php new file mode 100644 index 00000000000..2648a0dbcde --- /dev/null +++ b/src/Logging/TestDox/TestResult/TestResult.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Framework\TestStatus\TestStatus; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResult +{ + private TestMethod $test; + private TestStatus $status; + private ?Throwable $throwable; + + public function __construct(TestMethod $test, TestStatus $status, ?Throwable $throwable) + { + $this->test = $test; + $this->status = $status; + $this->throwable = $throwable; + } + + public function test(): TestMethod + { + return $this->test; + } + + public function status(): TestStatus + { + return $this->status; + } + + /** + * @phpstan-assert-if-true !null $this->throwable + */ + public function hasThrowable(): bool + { + return $this->throwable !== null; + } + + public function throwable(): ?Throwable + { + return $this->throwable; + } +} diff --git a/src/Logging/TestDox/TestResult/TestResultCollection.php b/src/Logging/TestDox/TestResult/TestResultCollection.php new file mode 100644 index 00000000000..5c4a4d64435 --- /dev/null +++ b/src/Logging/TestDox/TestResult/TestResultCollection.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResultCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $testResults; + + /** + * @param list $testResults + */ + public static function fromArray(array $testResults): self + { + return new self(...$testResults); + } + + private function __construct(TestResult ...$testResults) + { + $this->testResults = $testResults; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->testResults; + } + + public function getIterator(): TestResultCollectionIterator + { + return new TestResultCollectionIterator($this); + } +} diff --git a/src/Logging/TestDox/TestResult/TestResultCollectionIterator.php b/src/Logging/TestDox/TestResult/TestResultCollectionIterator.php new file mode 100644 index 00000000000..cf8ae7ac8b1 --- /dev/null +++ b/src/Logging/TestDox/TestResult/TestResultCollectionIterator.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function count; +use Iterator; + +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestResultCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $testResults; + private int $position = 0; + + public function __construct(TestResultCollection $testResults) + { + $this->testResults = $testResults->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->testResults); + } + + public function key(): int + { + return $this->position; + } + + public function current(): TestResult + { + return $this->testResults[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/Logging/TestDox/TestResult/TestResultCollector.php b/src/Logging/TestDox/TestResult/TestResultCollector.php new file mode 100644 index 00000000000..78bd819a615 --- /dev/null +++ b/src/Logging/TestDox/TestResult/TestResultCollector.php @@ -0,0 +1,383 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use function array_merge; +use function assert; +use function is_subclass_of; +use function ksort; +use function uksort; +use function usort; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Facade; +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\Passed; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Logging\TestDox\TestResult as TestDoxTestMethod; +use PHPUnit\TestRunner\IssueFilter; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestResultCollector +{ + private readonly IssueFilter $issueFilter; + + /** + * @var array> + */ + private array $tests = []; + private ?TestStatus $status = null; + private ?Throwable $throwable = null; + private bool $prepared = false; + + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $this->issueFilter = $issueFilter; + + $this->registerSubscribers($facade); + } + + /** + * @return array + */ + public function testMethodsGroupedByClass(): array + { + $result = []; + + foreach ($this->tests as $prettifiedClassName => $tests) { + $testsByDeclaringClass = []; + + foreach ($tests as $test) { + $declaringClassName = new ReflectionMethod($test->test()->className(), $test->test()->methodName())->getDeclaringClass()->getName(); + + if (!isset($testsByDeclaringClass[$declaringClassName])) { + $testsByDeclaringClass[$declaringClassName] = []; + } + + $testsByDeclaringClass[$declaringClassName][] = $test; + } + + foreach ($testsByDeclaringClass as $declaringClassName) { + usort( + $declaringClassName, + static function (TestDoxTestMethod $a, TestDoxTestMethod $b): int + { + return $a->test()->line() <=> $b->test()->line(); + }, + ); + } + + uksort( + $testsByDeclaringClass, + /** + * @param class-string $a + * @param class-string $b + */ + static function (string $a, string $b): int + { + if (is_subclass_of($b, $a)) { + return -1; + } + + if (is_subclass_of($a, $b)) { + return 1; + } + + return 0; + }, + ); + + $tests = []; + + foreach ($testsByDeclaringClass as $_tests) { + $tests = array_merge($tests, $_tests); + } + + $result[$prettifiedClassName] = TestResultCollection::fromArray($tests); + } + + ksort($result); + + return $result; + } + + public function testPrepared(Prepared $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->status = TestStatus::unknown(); + $this->throwable = null; + $this->prepared = true; + } + + public function testErrored(Errored $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->status = TestStatus::error($event->throwable()->message()); + $this->throwable = $event->throwable(); + + if (!$this->prepared) { + $test = $event->test(); + + assert($test instanceof TestMethod); + + $this->process($test); + } + } + + public function testFailed(Failed $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->status = TestStatus::failure($event->throwable()->message()); + $this->throwable = $event->throwable(); + } + + public function testPassed(Passed $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::success()); + } + + public function testSkipped(Skipped $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::skipped($event->message())); + } + + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::incomplete($event->throwable()->message())); + + $this->throwable = $event->throwable(); + } + + public function testConsideredRisky(ConsideredRisky $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::risky()); + } + + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredNotice(NoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::notice()); + } + + public function testTriggeredWarning(WarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::notice()); + } + + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event, true)) { + return; + } + + if ($event->ignoredByBaseline()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $this->updateTestStatus(TestStatus::error()); + } + + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + if ($event->ignoredByTest()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + /** + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + if (!$event->test()->isTestMethod()) { + return; + } + + $test = $event->test(); + + assert($test instanceof TestMethod); + + $this->process($test); + + $this->status = null; + $this->throwable = null; + $this->prepared = false; + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new TestConsideredRiskySubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestFinishedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestPassedSubscriber($this), + new TestPreparedSubscriber($this), + new TestSkippedSubscriber($this), + new TestTriggeredDeprecationSubscriber($this), + new TestTriggeredNoticeSubscriber($this), + new TestTriggeredPhpDeprecationSubscriber($this), + new TestTriggeredPhpNoticeSubscriber($this), + new TestTriggeredPhpunitDeprecationSubscriber($this), + new TestTriggeredPhpunitErrorSubscriber($this), + new TestTriggeredPhpunitWarningSubscriber($this), + new TestTriggeredPhpWarningSubscriber($this), + new TestTriggeredWarningSubscriber($this), + ); + } + + private function updateTestStatus(TestStatus $status): void + { + if ($this->status !== null && + $this->status->isMoreImportantThan($status)) { + return; + } + + $this->status = $status; + } + + private function process(TestMethod $test): void + { + if (!isset($this->tests[$test->testDox()->prettifiedClassName()])) { + $this->tests[$test->testDox()->prettifiedClassName()] = []; + } + + $this->tests[$test->testDox()->prettifiedClassName()][] = new TestDoxTestMethod( + $test, + $this->status, + $this->throwable, + ); + } +} diff --git a/src/Metadata/After.php b/src/Metadata/After.php new file mode 100644 index 00000000000..14413639064 --- /dev/null +++ b/src/Metadata/After.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class After extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isAfter(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/AfterClass.php b/src/Metadata/AfterClass.php new file mode 100644 index 00000000000..7dcb96fd7c2 --- /dev/null +++ b/src/Metadata/AfterClass.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterClass extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isAfterClass(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/AllowMockObjectsWithoutExpectations.php b/src/Metadata/AllowMockObjectsWithoutExpectations.php new file mode 100644 index 00000000000..cb6bbea4156 --- /dev/null +++ b/src/Metadata/AllowMockObjectsWithoutExpectations.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AllowMockObjectsWithoutExpectations extends Metadata +{ + public function isAllowMockObjectsWithoutExpectations(): true + { + return true; + } +} diff --git a/src/Metadata/Api/CodeCoverage.php b/src/Metadata/Api/CodeCoverage.php new file mode 100644 index 00000000000..f276623b70a --- /dev/null +++ b/src/Metadata/Api/CodeCoverage.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\CoversClass; +use PHPUnit\Metadata\CoversClassesThatExtendClass; +use PHPUnit\Metadata\CoversClassesThatImplementInterface; +use PHPUnit\Metadata\CoversFunction; +use PHPUnit\Metadata\CoversMethod; +use PHPUnit\Metadata\CoversNamespace; +use PHPUnit\Metadata\CoversTrait; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\UsesClass; +use PHPUnit\Metadata\UsesClassesThatExtendClass; +use PHPUnit\Metadata\UsesClassesThatImplementInterface; +use PHPUnit\Metadata\UsesFunction; +use PHPUnit\Metadata\UsesMethod; +use PHPUnit\Metadata\UsesNamespace; +use PHPUnit\Metadata\UsesTrait; +use SebastianBergmann\CodeCoverage\Test\Target\Target; +use SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverage +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function coversTargets(string $className, string $methodName): TargetCollection + { + $targets = []; + + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversNamespace()) { + assert($metadata instanceof CoversNamespace); + + $targets[] = Target::forNamespace($metadata->namespace()); + } + + if ($metadata->isCoversClass()) { + assert($metadata instanceof CoversClass); + + $targets[] = Target::forClass($metadata->className()); + } + + if ($metadata->isCoversClassesThatExtendClass()) { + assert($metadata instanceof CoversClassesThatExtendClass); + + $targets[] = Target::forClassesThatExtendClass($metadata->className()); + } + + if ($metadata->isCoversClassesThatImplementInterface()) { + assert($metadata instanceof CoversClassesThatImplementInterface); + + $targets[] = Target::forClassesThatImplementInterface($metadata->interfaceName()); + } + + if ($metadata->isCoversMethod()) { + assert($metadata instanceof CoversMethod); + + $targets[] = Target::forMethod($metadata->className(), $metadata->methodName()); + } + + if ($metadata->isCoversFunction()) { + assert($metadata instanceof CoversFunction); + + $targets[] = Target::forFunction($metadata->functionName()); + } + + if ($metadata->isCoversTrait()) { + assert($metadata instanceof CoversTrait); + + $targets[] = Target::forTrait($metadata->traitName()); + } + } + + return TargetCollection::fromArray($targets); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function usesTargets(string $className, string $methodName): TargetCollection + { + $targets = []; + + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isUsesNamespace()) { + assert($metadata instanceof UsesNamespace); + + $targets[] = Target::forNamespace($metadata->namespace()); + } + + if ($metadata->isUsesClass()) { + assert($metadata instanceof UsesClass); + + $targets[] = Target::forClass($metadata->className()); + } + + if ($metadata->isUsesClassesThatExtendClass()) { + assert($metadata instanceof UsesClassesThatExtendClass); + + $targets[] = Target::forClassesThatExtendClass($metadata->className()); + } + + if ($metadata->isUsesClassesThatImplementInterface()) { + assert($metadata instanceof UsesClassesThatImplementInterface); + + $targets[] = Target::forClassesThatImplementInterface($metadata->interfaceName()); + } + + if ($metadata->isUsesMethod()) { + assert($metadata instanceof UsesMethod); + + $targets[] = Target::forMethod($metadata->className(), $metadata->methodName()); + } + + if ($metadata->isUsesFunction()) { + assert($metadata instanceof UsesFunction); + + $targets[] = Target::forFunction($metadata->functionName()); + } + + if ($metadata->isUsesTrait()) { + assert($metadata instanceof UsesTrait); + + $targets[] = Target::forTrait($metadata->traitName()); + } + } + + return TargetCollection::fromArray($targets); + } + + public function shouldCodeCoverageBeCollectedFor(TestCase $test): bool + { + $parser = Registry::parser(); + + if ($parser->forClass($test::class)->isCoversNothing()->isNotEmpty()) { + return false; + } + + return true; + } +} diff --git a/src/Metadata/Api/DataProvider.php b/src/Metadata/Api/DataProvider.php new file mode 100644 index 00000000000..b3800ed7403 --- /dev/null +++ b/src/Metadata/Api/DataProvider.php @@ -0,0 +1,359 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_key_exists; +use function assert; +use function count; +use function get_debug_type; +use function is_array; +use function is_int; +use function is_iterable; +use function is_string; +use function sprintf; +use PHPUnit\Event; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\InvalidDataProviderException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\DataProvider as DataProviderMetadata; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Metadata\Parser\Registry as MetadataRegistry; +use PHPUnit\Metadata\TestWith; +use PHPUnit\Util\Test; +use ReflectionMethod; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProvider +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @throws InvalidDataProviderException + * + * @return ?array + */ + public function providedData(string $className, string $methodName): ?array + { + $metadataCollection = MetadataRegistry::parser()->forMethod($className, $methodName); + $dataProvider = $metadataCollection->isDataProvider(); + $testWith = $metadataCollection->isTestWith(); + + if ($dataProvider->isEmpty() && $testWith->isEmpty()) { + return null; + } + + $testMethod = new ReflectionMethod($className, $methodName); + + if ($dataProvider->isNotEmpty()) { + if ($testWith->isNotEmpty()) { + $this->triggerWarningForMixingOfDataProviderAndTestWith($testMethod); + } + + return $this->dataProvidedByMethods($className, $testMethod, $dataProvider); + } + + return $this->dataProvidedByMetadata($testMethod, $testWith); + } + + /** + * @param class-string $testClassName + * + * @throws InvalidDataProviderException + * + * @return array + */ + private function dataProvidedByMethods(string $testClassName, ReflectionMethod $testMethod, MetadataCollection $dataProvider): array + { + $testMethodValueObject = new Event\Code\ClassMethod( + $testClassName, + $testMethod->getName(), + ); + + $methodsCalled = []; + $result = []; + $testMethodNumberOfParameters = $testMethod->getNumberOfParameters(); + $testMethodIsNonVariadic = !$testMethod->isVariadic(); + + foreach ($dataProvider as $_dataProvider) { + assert($_dataProvider instanceof DataProviderMetadata); + + $providerLabel = $_dataProvider->className() . '::' . $_dataProvider->methodName(); + $dataProviderMethod = new Event\Code\ClassMethod($_dataProvider->className(), $_dataProvider->methodName()); + $validateArgumentCount = $testMethodIsNonVariadic && $_dataProvider->validateArgumentCount(); + + Event\Facade::emitter()->dataProviderMethodCalled( + $testMethodValueObject, + $dataProviderMethod, + ); + + $methodsCalled[] = $dataProviderMethod; + + try { + $method = new ReflectionMethod($_dataProvider->className(), $_dataProvider->methodName()); + $className = $_dataProvider->className(); + $methodName = $_dataProvider->methodName(); + + if (Test::isTestMethod($method)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Method %s::%s() used by test method %s::%s() is also a test method', + $_dataProvider->className(), + $_dataProvider->methodName(), + $testMethod->getDeclaringClass()->getName(), + $testMethod->getName(), + ), + ); + } + + if (!$method->isPublic()) { + throw new InvalidDataProviderException( + sprintf( + 'Data Provider method %s::%s() is not public', + $className, + $methodName, + ), + ); + } + + if (!$method->isStatic()) { + throw new InvalidDataProviderException( + sprintf( + 'Data Provider method %s::%s() is not static', + $className, + $methodName, + ), + ); + } + + if ($method->getNumberOfParameters() > 0) { + throw new InvalidDataProviderException( + sprintf( + 'Data Provider method %s::%s() expects an argument', + $className, + $methodName, + ), + ); + } + + /** @phpstan-ignore staticMethod.dynamicName */ + $data = $className::$methodName(); + + if (!is_iterable($data)) { + throw new InvalidDataProviderException( + sprintf( + 'Data Provider method %s::%s() does not return an iterable', + $className, + $methodName, + ), + ); + } + } catch (Throwable $e) { + Event\Facade::emitter()->dataProviderMethodFinished( + $testMethodValueObject, + ...$methodsCalled, + ); + + throw InvalidDataProviderException::forException($e, $providerLabel); + } + + try { + foreach ($data as $key => $value) { + if (!is_int($key) && !is_string($key)) { + throw new InvalidDataProviderException( + sprintf( + 'The key must be an integer or a string, %s given', + get_debug_type($key), + ), + ); + } + + if (!is_array($value)) { + throw new InvalidDataProviderException( + sprintf( + 'Data set %s provided by %s is invalid, expected array but got %s', + $this->formatKey($key), + $providerLabel, + get_debug_type($value), + ), + ); + } + + if ($validateArgumentCount && $testMethodNumberOfParameters < count($value)) { + $this->triggerWarningForArgumentCount( + $testMethod, + $this->formatKey($key), + $providerLabel, + count($value), + $testMethodNumberOfParameters, + ); + } + + if (is_int($key)) { + $result[] = new ProvidedData($providerLabel, $value); + + continue; + } + + if (array_key_exists($key, $result)) { + throw new InvalidDataProviderException( + sprintf( + 'The key "%s" has already been defined by provider %s', + $key, + $result[$key]->label(), + ), + ); + } + + $result[$key] = new ProvidedData($providerLabel, $value); + } + } catch (Throwable $e) { + Event\Facade::emitter()->dataProviderMethodFinished( + $testMethodValueObject, + ...$methodsCalled, + ); + + throw new InvalidDataProviderException( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + } + + Event\Facade::emitter()->dataProviderMethodFinished( + $testMethodValueObject, + ...$methodsCalled, + ); + + if ($result === []) { + throw new InvalidDataProviderException( + 'Empty data set provided by data provider', + ); + } + + return $result; + } + + /** + * @return array + */ + private function dataProvidedByMetadata(ReflectionMethod $testMethod, MetadataCollection $testWith): array + { + $result = []; + + foreach ($testWith as $i => $_testWith) { + assert($_testWith instanceof TestWith); + + $providerLabel = sprintf('TestWith#%s attribute', $i); + + if ($_testWith->hasName()) { + $key = $_testWith->name(); + + if (array_key_exists($key, $result)) { + throw new InvalidDataProviderException( + sprintf( + 'The key "%s" has already been defined by %s', + $key, + $result[$key]->label(), + ), + ); + } + + $result[$key] = new ProvidedData($providerLabel, $_testWith->data()); + } else { + $result[] = new ProvidedData($providerLabel, $_testWith->data()); + } + } + + $testMethodNumberOfParameters = $testMethod->getNumberOfParameters(); + $testMethodIsNonVariadic = !$testMethod->isVariadic(); + + foreach ($result as $key => $providedData) { + $value = $providedData->value(); + + if (!is_array($value)) { + throw new InvalidDataProviderException( + sprintf( + 'Data set %s provided by %s is invalid, expected array but got %s', + $this->formatKey($key), + $providedData->label(), + get_debug_type($value), + ), + ); + } + + if ($testMethodIsNonVariadic && $testMethodNumberOfParameters < count($value)) { + $this->triggerWarningForArgumentCount( + $testMethod, + $this->formatKey($key), + $providedData->label(), + count($value), + $testMethodNumberOfParameters, + ); + } + } + + return $result; + } + + /** + * @param int|non-empty-string $key + * + * @return non-empty-string + */ + private function formatKey(int|string $key): string + { + return is_int($key) ? '#' . $key : '"' . $key . '"'; + } + + private function triggerWarningForMixingOfDataProviderAndTestWith(ReflectionMethod $method): void + { + Event\Facade::emitter()->testTriggeredPhpunitWarning( + $this->testValueObject($method), + 'Mixing #[DataProvider*] and #[TestWith*] attributes is not supported, only the data provided by #[DataProvider*] will be used', + ); + } + + private function triggerWarningForArgumentCount(ReflectionMethod $method, string $key, string $label, int $numberOfValues, int $testMethodNumberOfParameters): void + { + Event\Facade::emitter()->testTriggeredPhpunitWarning( + $this->testValueObject($method), + sprintf( + 'Data set %s provided by %s has more arguments (%d) than the test method accepts (%d)', + $key, + $label, + $numberOfValues, + $testMethodNumberOfParameters, + ), + ); + } + + private function testValueObject(ReflectionMethod $method): TestMethod + { + return new TestMethod( + $method->getDeclaringClass()->getName(), + $method->getName(), + $method->getFileName(), + $method->getStartLine(), + Event\Code\TestDoxBuilder::fromClassNameAndMethodName( + $method->getDeclaringClass()->getName(), + $method->getName(), + ), + MetadataCollection::fromArray([]), + Event\TestData\TestDataCollection::fromArray([]), + ); + } +} diff --git a/src/Metadata/Api/Dependencies.php b/src/Metadata/Api/Dependencies.php new file mode 100644 index 00000000000..3ba35568fb9 --- /dev/null +++ b/src/Metadata/Api/Dependencies.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use PHPUnit\Framework\ExecutionOrderDependency; +use PHPUnit\Metadata\DependsOnClass; +use PHPUnit\Metadata\DependsOnMethod; +use PHPUnit\Metadata\Parser\Registry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Dependencies +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public static function dependencies(string $className, string $methodName): array + { + $dependencies = []; + + foreach (Registry::parser()->forClassAndMethod($className, $methodName)->isDepends() as $metadata) { + if ($metadata->isDependsOnClass()) { + assert($metadata instanceof DependsOnClass); + + $dependencies[] = ExecutionOrderDependency::forClass($metadata); + + continue; + } + + assert($metadata instanceof DependsOnMethod); + + if ($metadata->methodName() === '') { + $dependencies[] = ExecutionOrderDependency::invalid(); + + continue; + } + + $dependencies[] = ExecutionOrderDependency::forMethod($metadata); + } + + return $dependencies; + } +} diff --git a/src/Metadata/Api/Groups.php b/src/Metadata/Api/Groups.php new file mode 100644 index 00000000000..aa2cbf43fd9 --- /dev/null +++ b/src/Metadata/Api/Groups.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_flip; +use function array_key_exists; +use function array_unique; +use function assert; +use function strtolower; +use function trim; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\CoversClass; +use PHPUnit\Metadata\CoversFunction; +use PHPUnit\Metadata\Group; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\RequiresPhpExtension; +use PHPUnit\Metadata\UsesClass; +use PHPUnit\Metadata\UsesFunction; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Groups +{ + /** + * @var array> + */ + private static array $groupCache = []; + + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public function groups(string $className, string $methodName, bool $includeVirtual = true): array + { + $key = $className . '::' . $methodName . '::' . $includeVirtual; + + if (array_key_exists($key, self::$groupCache)) { + return self::$groupCache[$key]; + } + + $groups = []; + + foreach (Registry::parser()->forClassAndMethod($className, $methodName)->isGroup() as $group) { + assert($group instanceof Group); + + $groups[] = $group->groupName(); + } + + if (!$includeVirtual) { + return self::$groupCache[$key] = array_unique($groups); + } + + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isCoversClass()) { + assert($metadata instanceof CoversClass); + + $groups[] = '__phpunit_covers_' . $this->canonicalizeName($metadata->className()); + + continue; + } + + if ($metadata->isCoversFunction()) { + assert($metadata instanceof CoversFunction); + + $groups[] = '__phpunit_covers_' . $this->canonicalizeName($metadata->functionName()); + + continue; + } + + if ($metadata->isUsesClass()) { + assert($metadata instanceof UsesClass); + + $groups[] = '__phpunit_uses_' . $this->canonicalizeName($metadata->className()); + + continue; + } + + if ($metadata->isUsesFunction()) { + assert($metadata instanceof UsesFunction); + + $groups[] = '__phpunit_uses_' . $this->canonicalizeName($metadata->functionName()); + + continue; + } + + if ($metadata->isRequiresPhpExtension()) { + assert($metadata instanceof RequiresPhpExtension); + + $groups[] = '__phpunit_requires_php_extension' . $this->canonicalizeName($metadata->extension()); + } + } + + return self::$groupCache[$key] = array_unique($groups); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function size(string $className, string $methodName): TestSize + { + $groups = array_flip($this->groups($className, $methodName)); + + if (isset($groups['large'])) { + return TestSize::large(); + } + + if (isset($groups['medium'])) { + return TestSize::medium(); + } + + if (isset($groups['small'])) { + return TestSize::small(); + } + + return TestSize::unknown(); + } + + private function canonicalizeName(string $name): string + { + return strtolower(trim($name, '\\')); + } +} diff --git a/src/Metadata/Api/HookMethods.php b/src/Metadata/Api/HookMethods.php new file mode 100644 index 00000000000..8981459a4f8 --- /dev/null +++ b/src/Metadata/Api/HookMethods.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function assert; +use function class_exists; +use function in_array; +use function strtolower; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\After; +use PHPUnit\Metadata\AfterClass; +use PHPUnit\Metadata\Before; +use PHPUnit\Metadata\BeforeClass; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\PostCondition; +use PHPUnit\Metadata\PreCondition; +use PHPUnit\Runner\HookMethod; +use PHPUnit\Runner\HookMethodCollection; +use PHPUnit\Util\Reflection; +use ReflectionClass; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookMethods +{ + /** + * @var array + */ + private static array $hookMethods = []; + + /** + * @param class-string $className + * + * @return array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} + */ + public function hookMethods(string $className): array + { + if (!class_exists($className)) { + return self::emptyHookMethodsArray(); + } + + if (isset(self::$hookMethods[$className])) { + return self::$hookMethods[$className]; + } + + self::$hookMethods[$className] = self::emptyHookMethodsArray(); + + foreach (Reflection::methodsDeclaredDirectlyInTestClass(new ReflectionClass($className)) as $method) { + $methodName = $method->getName(); + $metadata = Registry::parser()->forMethod($className, $methodName); + + if ($method->isStatic()) { + if ($metadata->isBeforeClass()->isNotEmpty()) { + $beforeClass = $metadata->isBeforeClass()->asArray()[0]; + assert($beforeClass instanceof BeforeClass); + + self::$hookMethods[$className]['beforeClass']->add( + new HookMethod($methodName, $beforeClass->priority()), + ); + } + + if ($metadata->isAfterClass()->isNotEmpty()) { + $afterClass = $metadata->isAfterClass()->asArray()[0]; + assert($afterClass instanceof AfterClass); + + self::$hookMethods[$className]['afterClass']->add( + new HookMethod($methodName, $afterClass->priority()), + ); + } + } + + if ($metadata->isBefore()->isNotEmpty()) { + $before = $metadata->isBefore()->asArray()[0]; + assert($before instanceof Before); + + self::$hookMethods[$className]['before']->add( + new HookMethod($methodName, $before->priority()), + ); + } + + if ($metadata->isPreCondition()->isNotEmpty()) { + $preCondition = $metadata->isPreCondition()->asArray()[0]; + assert($preCondition instanceof PreCondition); + + self::$hookMethods[$className]['preCondition']->add( + new HookMethod($methodName, $preCondition->priority()), + ); + } + + if ($metadata->isPostCondition()->isNotEmpty()) { + $postCondition = $metadata->isPostCondition()->asArray()[0]; + assert($postCondition instanceof PostCondition); + + self::$hookMethods[$className]['postCondition']->add( + new HookMethod($methodName, $postCondition->priority()), + ); + } + + if ($metadata->isAfter()->isNotEmpty()) { + $after = $metadata->isAfter()->asArray()[0]; + assert($after instanceof After); + + self::$hookMethods[$className]['after']->add( + new HookMethod($methodName, $after->priority()), + ); + } + } + + return self::$hookMethods[$className]; + } + + public function isHookMethod(ReflectionMethod $method): bool + { + $defaultNames = [ + 'setupbeforeclass', + 'setup', + 'assertpreconditions', + 'assertpostconditions', + 'teardown', + 'teardownafterclass', + ]; + + if (in_array(strtolower($method->getName()), $defaultNames, true)) { + return true; + } + + $metadata = Registry::parser()->forMethod($method->getDeclaringClass()->getName(), $method->getName()); + + return $metadata->isBeforeClass()->isNotEmpty() || + $metadata->isBefore()->isNotEmpty() || + $metadata->isPreCondition()->isNotEmpty() || + $metadata->isPostCondition()->isNotEmpty() || + $metadata->isAfter()->isNotEmpty() || + $metadata->isAfterClass()->isNotEmpty(); + } + + /** + * @return array{beforeClass: HookMethodCollection, before: HookMethodCollection, preCondition: HookMethodCollection, postCondition: HookMethodCollection, after: HookMethodCollection, afterClass: HookMethodCollection} + */ + private function emptyHookMethodsArray(): array + { + return [ + 'beforeClass' => HookMethodCollection::defaultBeforeClass(), + 'before' => HookMethodCollection::defaultBefore(), + 'preCondition' => HookMethodCollection::defaultPreCondition(), + 'postCondition' => HookMethodCollection::defaultPostCondition(), + 'after' => HookMethodCollection::defaultAfter(), + 'afterClass' => HookMethodCollection::defaultAfterClass(), + ]; + } +} diff --git a/src/Metadata/Api/ProvidedData.php b/src/Metadata/Api/ProvidedData.php new file mode 100644 index 00000000000..7d21766bc95 --- /dev/null +++ b/src/Metadata/Api/ProvidedData.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ProvidedData +{ + /** + * @var non-empty-string + */ + private string $label; + private mixed $value; + + /** + * @param non-empty-string $label + */ + public function __construct(string $label, mixed $value) + { + $this->label = $label; + $this->value = $value; + } + + /** + * @return non-empty-string + */ + public function label(): string + { + return $this->label; + } + + public function value(): mixed + { + return $this->value; + } +} diff --git a/src/Metadata/Api/Requirements.php b/src/Metadata/Api/Requirements.php new file mode 100644 index 00000000000..c6870ca7a3a --- /dev/null +++ b/src/Metadata/Api/Requirements.php @@ -0,0 +1,213 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use const PHP_OS; +use const PHP_OS_FAMILY; +use const PHP_VERSION; +use function addcslashes; +use function array_column; +use function array_key_exists; +use function assert; +use function extension_loaded; +use function function_exists; +use function in_array; +use function ini_get; +use function method_exists; +use function phpversion; +use function preg_match; +use function sprintf; +use PHPUnit\Metadata\Parser\Registry; +use PHPUnit\Metadata\RequiresEnvironmentVariable; +use PHPUnit\Metadata\RequiresFunction; +use PHPUnit\Metadata\RequiresMethod; +use PHPUnit\Metadata\RequiresOperatingSystem; +use PHPUnit\Metadata\RequiresOperatingSystemFamily; +use PHPUnit\Metadata\RequiresPhp; +use PHPUnit\Metadata\RequiresPhpExtension; +use PHPUnit\Metadata\RequiresPhpunit; +use PHPUnit\Metadata\RequiresPhpunitExtension; +use PHPUnit\Metadata\RequiresSetting; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Requirements +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return list + */ + public function requirementsNotSatisfiedFor(string $className, string $methodName): array + { + $notSatisfied = []; + + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isRequiresPhp()) { + assert($metadata instanceof RequiresPhp); + + if (!$metadata->versionRequirement()->isSatisfiedBy(PHP_VERSION)) { + $notSatisfied[] = sprintf( + 'PHP %s is required.', + $metadata->versionRequirement()->asString(), + ); + } + } + + if ($metadata->isRequiresPhpExtension()) { + assert($metadata instanceof RequiresPhpExtension); + + $extensionVersion = phpversion($metadata->extension()); + + if ($extensionVersion === false) { + $extensionVersion = ''; + } + + if (!extension_loaded($metadata->extension()) || + ($metadata->hasVersionRequirement() && + !$metadata->versionRequirement()->isSatisfiedBy($extensionVersion))) { + $notSatisfied[] = sprintf( + 'PHP extension %s%s is required.', + $metadata->extension(), + $metadata->hasVersionRequirement() ? (' ' . $metadata->versionRequirement()->asString()) : '', + ); + } + } + + if ($metadata->isRequiresPhpunit()) { + assert($metadata instanceof RequiresPhpunit); + + if (!$metadata->versionRequirement()->isSatisfiedBy(Version::id())) { + $notSatisfied[] = sprintf( + 'PHPUnit %s is required.', + $metadata->versionRequirement()->asString(), + ); + } + } + + if ($metadata->isRequiresPhpunitExtension()) { + assert($metadata instanceof RequiresPhpunitExtension); + + $configuration = ConfigurationRegistry::get(); + + $extensionBootstrappers = array_column($configuration->extensionBootstrappers(), 'className'); + + if ($configuration->noExtensions() || !in_array($metadata->extensionClass(), $extensionBootstrappers, true)) { + $notSatisfied[] = sprintf( + 'PHPUnit extension "%s" is required.', + $metadata->extensionClass(), + ); + } + } + + if ($metadata->isRequiresEnvironmentVariable()) { + assert($metadata instanceof RequiresEnvironmentVariable); + + if (!array_key_exists($metadata->environmentVariableName(), $_ENV) || + $metadata->value() === null && $_ENV[$metadata->environmentVariableName()] === '') { + $notSatisfied[] = sprintf('Environment variable "%s" is required.', $metadata->environmentVariableName()); + + continue; + } + + if ($metadata->value() !== null && $_ENV[$metadata->environmentVariableName()] !== $metadata->value()) { + $notSatisfied[] = sprintf( + 'Environment variable "%s" is required to be "%s".', + $metadata->environmentVariableName(), + $metadata->value(), + ); + } + } + + if ($metadata->isRequiresOperatingSystemFamily()) { + assert($metadata instanceof RequiresOperatingSystemFamily); + + if ($metadata->operatingSystemFamily() !== PHP_OS_FAMILY) { + $notSatisfied[] = sprintf( + 'Operating system %s is required.', + $metadata->operatingSystemFamily(), + ); + } + } + + if ($metadata->isRequiresOperatingSystem()) { + assert($metadata instanceof RequiresOperatingSystem); + + $pattern = sprintf( + '/%s/i', + addcslashes($metadata->operatingSystem(), '/'), + ); + + if (preg_match($pattern, PHP_OS) === 0) { + $notSatisfied[] = sprintf( + 'Operating system %s is required.', + $metadata->operatingSystem(), + ); + } + } + + if ($metadata->isRequiresFunction()) { + assert($metadata instanceof RequiresFunction); + + if (!function_exists($metadata->functionName())) { + $notSatisfied[] = sprintf( + 'Function %s() is required.', + $metadata->functionName(), + ); + } + } + + if ($metadata->isRequiresMethod()) { + assert($metadata instanceof RequiresMethod); + + if (!method_exists($metadata->className(), $metadata->methodName())) { + $notSatisfied[] = sprintf( + 'Method %s::%s() is required.', + $metadata->className(), + $metadata->methodName(), + ); + } + } + + if ($metadata->isRequiresSetting()) { + assert($metadata instanceof RequiresSetting); + + if (ini_get($metadata->setting()) !== $metadata->value()) { + $notSatisfied[] = sprintf( + 'Setting "%s" is required to be "%s".', + $metadata->setting(), + $metadata->value(), + ); + } + } + } + + return $notSatisfied; + } + + public function requiresXdebug(string $className, string $methodName): bool + { + foreach (Registry::parser()->forClassAndMethod($className, $methodName) as $metadata) { + if ($metadata->isRequiresPhpExtension()) { + if ($metadata->extension() === 'xdebug') { + return true; + } + } + } + + return false; + } +} diff --git a/src/Metadata/BackupGlobals.php b/src/Metadata/BackupGlobals.php new file mode 100644 index 00000000000..5d9478443df --- /dev/null +++ b/src/Metadata/BackupGlobals.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackupGlobals extends Metadata +{ + private bool $enabled; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, bool $enabled) + { + parent::__construct($level); + + $this->enabled = $enabled; + } + + public function isBackupGlobals(): true + { + return true; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Metadata/BackupStaticProperties.php b/src/Metadata/BackupStaticProperties.php new file mode 100644 index 00000000000..a07698eeb13 --- /dev/null +++ b/src/Metadata/BackupStaticProperties.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackupStaticProperties extends Metadata +{ + private bool $enabled; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, bool $enabled) + { + parent::__construct($level); + + $this->enabled = $enabled; + } + + public function isBackupStaticProperties(): true + { + return true; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Metadata/Before.php b/src/Metadata/Before.php new file mode 100644 index 00000000000..08372f76ca3 --- /dev/null +++ b/src/Metadata/Before.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Before extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isBefore(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/BeforeClass.php b/src/Metadata/BeforeClass.php new file mode 100644 index 00000000000..c5646320789 --- /dev/null +++ b/src/Metadata/BeforeClass.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeClass extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isBeforeClass(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/CoversClass.php b/src/Metadata/CoversClass.php new file mode 100644 index 00000000000..e573952b639 --- /dev/null +++ b/src/Metadata/CoversClass.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClass extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param int<0, 1> $level + * @param class-string $className + */ + protected function __construct(int $level, string $className) + { + parent::__construct($level); + + $this->className = $className; + } + + public function isCoversClass(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Metadata/CoversClassesThatExtendClass.php b/src/Metadata/CoversClassesThatExtendClass.php new file mode 100644 index 00000000000..7feb40d7098 --- /dev/null +++ b/src/Metadata/CoversClassesThatExtendClass.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClassesThatExtendClass extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param int<0, 1> $level + * @param class-string $className + */ + protected function __construct(int $level, string $className) + { + parent::__construct($level); + + $this->className = $className; + } + + public function isCoversClassesThatExtendClass(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Metadata/CoversClassesThatImplementInterface.php b/src/Metadata/CoversClassesThatImplementInterface.php new file mode 100644 index 00000000000..e980801ecb3 --- /dev/null +++ b/src/Metadata/CoversClassesThatImplementInterface.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversClassesThatImplementInterface extends Metadata +{ + /** + * @var class-string + */ + private string $interfaceName; + + /** + * @param int<0, 1> $level + * @param class-string $interfaceName + */ + protected function __construct(int $level, string $interfaceName) + { + parent::__construct($level); + + $this->interfaceName = $interfaceName; + } + + public function isCoversClassesThatImplementInterface(): true + { + return true; + } + + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} diff --git a/src/Metadata/CoversFunction.php b/src/Metadata/CoversFunction.php new file mode 100644 index 00000000000..4e953601f8e --- /dev/null +++ b/src/Metadata/CoversFunction.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversFunction extends Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param int<0, 1> $level + * @param non-empty-string $functionName + */ + protected function __construct(int $level, string $functionName) + { + parent::__construct($level); + + $this->functionName = $functionName; + } + + public function isCoversFunction(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Metadata/CoversMethod.php b/src/Metadata/CoversMethod.php new file mode 100644 index 00000000000..73092ff780e --- /dev/null +++ b/src/Metadata/CoversMethod.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversMethod extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + } + + public function isCoversMethod(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Metadata/CoversNamespace.php b/src/Metadata/CoversNamespace.php new file mode 100644 index 00000000000..ef7452a66a4 --- /dev/null +++ b/src/Metadata/CoversNamespace.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversNamespace extends Metadata +{ + /** + * @var non-empty-string + */ + private string $namespace; + + /** + * @param int<0, 1> $level + * @param non-empty-string $namespace + */ + protected function __construct(int $level, string $namespace) + { + parent::__construct($level); + + $this->namespace = $namespace; + } + + public function isCoversNamespace(): true + { + return true; + } + + /** + * @return class-string + */ + public function namespace(): string + { + return $this->namespace; + } +} diff --git a/src/Metadata/CoversNothing.php b/src/Metadata/CoversNothing.php new file mode 100644 index 00000000000..c81e72765b4 --- /dev/null +++ b/src/Metadata/CoversNothing.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversNothing extends Metadata +{ + public function isCoversNothing(): true + { + return true; + } +} diff --git a/src/Metadata/CoversTrait.php b/src/Metadata/CoversTrait.php new file mode 100644 index 00000000000..2cad9dfb4ab --- /dev/null +++ b/src/Metadata/CoversTrait.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoversTrait extends Metadata +{ + /** + * @var trait-string + */ + private string $traitName; + + /** + * @param 0|1 $level + * @param trait-string $traitName + */ + protected function __construct(int $level, string $traitName) + { + parent::__construct($level); + + $this->traitName = $traitName; + } + + public function isCoversTrait(): true + { + return true; + } + + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} diff --git a/src/Metadata/DataProvider.php b/src/Metadata/DataProvider.php new file mode 100644 index 00000000000..ca048bbaac6 --- /dev/null +++ b/src/Metadata/DataProvider.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DataProvider extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + private bool $validateArgumentCount; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName, bool $validateArgumentCount) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + $this->validateArgumentCount = $validateArgumentCount; + } + + public function isDataProvider(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function validateArgumentCount(): bool + { + return $this->validateArgumentCount; + } +} diff --git a/src/Metadata/DependsOnClass.php b/src/Metadata/DependsOnClass.php new file mode 100644 index 00000000000..fbc40fd144e --- /dev/null +++ b/src/Metadata/DependsOnClass.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DependsOnClass extends Metadata +{ + /** + * @var class-string + */ + private string $className; + private bool $deepClone; + private bool $shallowClone; + + /** + * @param int<0, 1> $level + * @param class-string $className + */ + protected function __construct(int $level, string $className, bool $deepClone, bool $shallowClone) + { + parent::__construct($level); + + $this->className = $className; + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + } + + public function isDependsOnClass(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + public function deepClone(): bool + { + return $this->deepClone; + } + + public function shallowClone(): bool + { + return $this->shallowClone; + } +} diff --git a/src/Metadata/DependsOnMethod.php b/src/Metadata/DependsOnMethod.php new file mode 100644 index 00000000000..82056a996f2 --- /dev/null +++ b/src/Metadata/DependsOnMethod.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DependsOnMethod extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + private bool $deepClone; + private bool $shallowClone; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName, bool $deepClone, bool $shallowClone) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + $this->deepClone = $deepClone; + $this->shallowClone = $shallowClone; + } + + public function isDependsOnMethod(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function deepClone(): bool + { + return $this->deepClone; + } + + public function shallowClone(): bool + { + return $this->shallowClone; + } +} diff --git a/src/Metadata/DisableReturnValueGenerationForTestDoubles.php b/src/Metadata/DisableReturnValueGenerationForTestDoubles.php new file mode 100644 index 00000000000..59cf34e2833 --- /dev/null +++ b/src/Metadata/DisableReturnValueGenerationForTestDoubles.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DisableReturnValueGenerationForTestDoubles extends Metadata +{ + public function isDisableReturnValueGenerationForTestDoubles(): true + { + return true; + } +} diff --git a/src/Metadata/DoesNotPerformAssertions.php b/src/Metadata/DoesNotPerformAssertions.php new file mode 100644 index 00000000000..e2925c8576b --- /dev/null +++ b/src/Metadata/DoesNotPerformAssertions.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DoesNotPerformAssertions extends Metadata +{ + public function isDoesNotPerformAssertions(): true + { + return true; + } +} diff --git a/src/Metadata/Exception/Exception.php b/src/Metadata/Exception/Exception.php new file mode 100644 index 00000000000..5d562f1a2fa --- /dev/null +++ b/src/Metadata/Exception/Exception.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} diff --git a/src/Metadata/Exception/InvalidAttributeException.php b/src/Metadata/Exception/InvalidAttributeException.php new file mode 100644 index 00000000000..9158de32851 --- /dev/null +++ b/src/Metadata/Exception/InvalidAttributeException.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidAttributeException extends RuntimeException implements Exception +{ + /** + * @param non-empty-string $attributeName + * @param non-empty-string $target + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $message + */ + public function __construct(string $attributeName, string $target, string $file, int $line, string $message) + { + parent::__construct( + sprintf( + 'Invalid attribute %s for %s in %s:%d%s%s', + $attributeName, + $target, + $file, + $line, + PHP_EOL, + $message, + ), + ); + } +} diff --git a/src/Metadata/Exception/InvalidVersionRequirementException.php b/src/Metadata/Exception/InvalidVersionRequirementException.php new file mode 100644 index 00000000000..359f723c1dc --- /dev/null +++ b/src/Metadata/Exception/InvalidVersionRequirementException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionRequirementException extends RuntimeException implements Exception +{ +} diff --git a/src/Metadata/Exception/NoVersionRequirementException.php b/src/Metadata/Exception/NoVersionRequirementException.php new file mode 100644 index 00000000000..299652cf0ab --- /dev/null +++ b/src/Metadata/Exception/NoVersionRequirementException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class NoVersionRequirementException extends RuntimeException implements Exception +{ +} diff --git a/src/Metadata/ExcludeGlobalVariableFromBackup.php b/src/Metadata/ExcludeGlobalVariableFromBackup.php new file mode 100644 index 00000000000..4f646dbdea7 --- /dev/null +++ b/src/Metadata/ExcludeGlobalVariableFromBackup.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExcludeGlobalVariableFromBackup extends Metadata +{ + /** + * @var non-empty-string + */ + private string $globalVariableName; + + /** + * @param int<0, 1> $level + * @param non-empty-string $globalVariableName + */ + protected function __construct(int $level, string $globalVariableName) + { + parent::__construct($level); + + $this->globalVariableName = $globalVariableName; + } + + public function isExcludeGlobalVariableFromBackup(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function globalVariableName(): string + { + return $this->globalVariableName; + } +} diff --git a/src/Metadata/ExcludeStaticPropertyFromBackup.php b/src/Metadata/ExcludeStaticPropertyFromBackup.php new file mode 100644 index 00000000000..21725e939dd --- /dev/null +++ b/src/Metadata/ExcludeStaticPropertyFromBackup.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExcludeStaticPropertyFromBackup extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $propertyName; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $propertyName + */ + protected function __construct(int $level, string $className, string $propertyName) + { + parent::__construct($level); + + $this->className = $className; + $this->propertyName = $propertyName; + } + + public function isExcludeStaticPropertyFromBackup(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function propertyName(): string + { + return $this->propertyName; + } +} diff --git a/src/Metadata/Group.php b/src/Metadata/Group.php new file mode 100644 index 00000000000..2ee2784f275 --- /dev/null +++ b/src/Metadata/Group.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Group extends Metadata +{ + /** + * @var non-empty-string + */ + private string $groupName; + + /** + * @param int<0, 1> $level + * @param non-empty-string $groupName + */ + protected function __construct(int $level, string $groupName) + { + parent::__construct($level); + + $this->groupName = $groupName; + } + + public function isGroup(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function groupName(): string + { + return $this->groupName; + } +} diff --git a/src/Metadata/IgnoreDeprecations.php b/src/Metadata/IgnoreDeprecations.php new file mode 100644 index 00000000000..be0f3a37169 --- /dev/null +++ b/src/Metadata/IgnoreDeprecations.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnoreDeprecations extends Metadata +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + + /** + * @param int<0, 1> $level + * @param null|non-empty-string $messagePattern + */ + protected function __construct(int $level, null|string $messagePattern) + { + parent::__construct($level); + + $this->messagePattern = $messagePattern; + } + + public function isIgnoreDeprecations(): true + { + return true; + } + + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} diff --git a/src/Metadata/IgnorePhpunitDeprecations.php b/src/Metadata/IgnorePhpunitDeprecations.php new file mode 100644 index 00000000000..5abcfa48521 --- /dev/null +++ b/src/Metadata/IgnorePhpunitDeprecations.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnorePhpunitDeprecations extends Metadata +{ + public function isIgnorePhpunitDeprecations(): true + { + return true; + } +} diff --git a/src/Metadata/IgnorePhpunitWarnings.php b/src/Metadata/IgnorePhpunitWarnings.php new file mode 100644 index 00000000000..e5f6ef524c5 --- /dev/null +++ b/src/Metadata/IgnorePhpunitWarnings.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IgnorePhpunitWarnings extends Metadata +{ + /** @var null|non-empty-string */ + private ?string $messagePattern; + + /** + * @param int<0, 1> $level + * @param null|non-empty-string $messagePattern + */ + protected function __construct(int $level, null|string $messagePattern) + { + parent::__construct($level); + + $this->messagePattern = $messagePattern; + } + + public function isIgnorePhpunitWarnings(): true + { + return true; + } + + /** + * @return null|non-empty-string + */ + public function messagePattern(): ?string + { + return $this->messagePattern; + } +} diff --git a/src/Metadata/Metadata.php b/src/Metadata/Metadata.php new file mode 100644 index 00000000000..d5685b1e394 --- /dev/null +++ b/src/Metadata/Metadata.php @@ -0,0 +1,1015 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; +use PHPUnit\Runner\Extension\Extension; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Metadata +{ + private const int CLASS_LEVEL = 0; + private const int METHOD_LEVEL = 1; + + /** + * @var int<0, 1> + */ + private int $level; + + public static function after(int $priority): After + { + return new After(self::METHOD_LEVEL, $priority); + } + + public static function afterClass(int $priority): AfterClass + { + return new AfterClass(self::METHOD_LEVEL, $priority); + } + + public static function allowMockObjectsWithoutExpectationsOnClass(): AllowMockObjectsWithoutExpectations + { + return new AllowMockObjectsWithoutExpectations(self::CLASS_LEVEL); + } + + public static function allowMockObjectsWithoutExpectationsOnMethod(): AllowMockObjectsWithoutExpectations + { + return new AllowMockObjectsWithoutExpectations(self::METHOD_LEVEL); + } + + public static function backupGlobalsOnClass(bool $enabled): BackupGlobals + { + return new BackupGlobals(self::CLASS_LEVEL, $enabled); + } + + public static function backupGlobalsOnMethod(bool $enabled): BackupGlobals + { + return new BackupGlobals(self::METHOD_LEVEL, $enabled); + } + + public static function backupStaticPropertiesOnClass(bool $enabled): BackupStaticProperties + { + return new BackupStaticProperties(self::CLASS_LEVEL, $enabled); + } + + public static function backupStaticPropertiesOnMethod(bool $enabled): BackupStaticProperties + { + return new BackupStaticProperties(self::METHOD_LEVEL, $enabled); + } + + public static function before(int $priority): Before + { + return new Before(self::METHOD_LEVEL, $priority); + } + + public static function beforeClass(int $priority): BeforeClass + { + return new BeforeClass(self::METHOD_LEVEL, $priority); + } + + /** + * @param non-empty-string $namespace + */ + public static function coversNamespace(string $namespace): CoversNamespace + { + return new CoversNamespace(self::CLASS_LEVEL, $namespace); + } + + /** + * @param class-string $className + */ + public static function coversClass(string $className): CoversClass + { + return new CoversClass(self::CLASS_LEVEL, $className); + } + + /** + * @param class-string $className + */ + public static function coversClassesThatExtendClass(string $className): CoversClassesThatExtendClass + { + return new CoversClassesThatExtendClass(self::CLASS_LEVEL, $className); + } + + /** + * @param class-string $interfaceName + */ + public static function coversClassesThatImplementInterface(string $interfaceName): CoversClassesThatImplementInterface + { + return new CoversClassesThatImplementInterface(self::CLASS_LEVEL, $interfaceName); + } + + /** + * @param trait-string $traitName + */ + public static function coversTrait(string $traitName): CoversTrait + { + return new CoversTrait(self::CLASS_LEVEL, $traitName); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function coversMethod(string $className, string $methodName): CoversMethod + { + return new CoversMethod(self::CLASS_LEVEL, $className, $methodName); + } + + /** + * @param non-empty-string $functionName + */ + public static function coversFunction(string $functionName): CoversFunction + { + return new CoversFunction(self::CLASS_LEVEL, $functionName); + } + + public static function coversNothingOnClass(): CoversNothing + { + return new CoversNothing(self::CLASS_LEVEL); + } + + public static function coversNothingOnMethod(): CoversNothing + { + return new CoversNothing(self::METHOD_LEVEL); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function dataProvider(string $className, string $methodName, bool $validateArgumentCount): DataProvider + { + return new DataProvider(self::METHOD_LEVEL, $className, $methodName, $validateArgumentCount); + } + + /** + * @param class-string $className + */ + public static function dependsOnClass(string $className, bool $deepClone, bool $shallowClone): DependsOnClass + { + return new DependsOnClass(self::METHOD_LEVEL, $className, $deepClone, $shallowClone); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function dependsOnMethod(string $className, string $methodName, bool $deepClone, bool $shallowClone): DependsOnMethod + { + return new DependsOnMethod(self::METHOD_LEVEL, $className, $methodName, $deepClone, $shallowClone); + } + + public static function disableReturnValueGenerationForTestDoubles(): DisableReturnValueGenerationForTestDoubles + { + return new DisableReturnValueGenerationForTestDoubles(self::CLASS_LEVEL); + } + + public static function doesNotPerformAssertionsOnClass(): DoesNotPerformAssertions + { + return new DoesNotPerformAssertions(self::CLASS_LEVEL); + } + + public static function doesNotPerformAssertionsOnMethod(): DoesNotPerformAssertions + { + return new DoesNotPerformAssertions(self::METHOD_LEVEL); + } + + /** + * @param non-empty-string $globalVariableName + */ + public static function excludeGlobalVariableFromBackupOnClass(string $globalVariableName): ExcludeGlobalVariableFromBackup + { + return new ExcludeGlobalVariableFromBackup(self::CLASS_LEVEL, $globalVariableName); + } + + /** + * @param non-empty-string $globalVariableName + */ + public static function excludeGlobalVariableFromBackupOnMethod(string $globalVariableName): ExcludeGlobalVariableFromBackup + { + return new ExcludeGlobalVariableFromBackup(self::METHOD_LEVEL, $globalVariableName); + } + + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public static function excludeStaticPropertyFromBackupOnClass(string $className, string $propertyName): ExcludeStaticPropertyFromBackup + { + return new ExcludeStaticPropertyFromBackup(self::CLASS_LEVEL, $className, $propertyName); + } + + /** + * @param class-string $className + * @param non-empty-string $propertyName + */ + public static function excludeStaticPropertyFromBackupOnMethod(string $className, string $propertyName): ExcludeStaticPropertyFromBackup + { + return new ExcludeStaticPropertyFromBackup(self::METHOD_LEVEL, $className, $propertyName); + } + + /** + * @param non-empty-string $groupName + */ + public static function groupOnClass(string $groupName): Group + { + return new Group(self::CLASS_LEVEL, $groupName); + } + + /** + * @param non-empty-string $groupName + */ + public static function groupOnMethod(string $groupName): Group + { + return new Group(self::METHOD_LEVEL, $groupName); + } + + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignoreDeprecationsOnClass(?string $messagePattern = null): IgnoreDeprecations + { + return new IgnoreDeprecations(self::CLASS_LEVEL, $messagePattern); + } + + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignoreDeprecationsOnMethod(?string $messagePattern = null): IgnoreDeprecations + { + return new IgnoreDeprecations(self::METHOD_LEVEL, $messagePattern); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public static function ignorePhpunitDeprecationsOnClass(): IgnorePhpunitDeprecations + { + return new IgnorePhpunitDeprecations(self::CLASS_LEVEL); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public static function ignorePhpunitDeprecationsOnMethod(): IgnorePhpunitDeprecations + { + return new IgnorePhpunitDeprecations(self::METHOD_LEVEL); + } + + public static function postCondition(int $priority): PostCondition + { + return new PostCondition(self::METHOD_LEVEL, $priority); + } + + public static function preCondition(int $priority): PreCondition + { + return new PreCondition(self::METHOD_LEVEL, $priority); + } + + public static function preserveGlobalStateOnClass(bool $enabled): PreserveGlobalState + { + return new PreserveGlobalState(self::CLASS_LEVEL, $enabled); + } + + public static function preserveGlobalStateOnMethod(bool $enabled): PreserveGlobalState + { + return new PreserveGlobalState(self::METHOD_LEVEL, $enabled); + } + + /** + * @param non-empty-string $functionName + */ + public static function requiresFunctionOnClass(string $functionName): RequiresFunction + { + return new RequiresFunction(self::CLASS_LEVEL, $functionName); + } + + /** + * @param non-empty-string $functionName + */ + public static function requiresFunctionOnMethod(string $functionName): RequiresFunction + { + return new RequiresFunction(self::METHOD_LEVEL, $functionName); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function requiresMethodOnClass(string $className, string $methodName): RequiresMethod + { + return new RequiresMethod(self::CLASS_LEVEL, $className, $methodName); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function requiresMethodOnMethod(string $className, string $methodName): RequiresMethod + { + return new RequiresMethod(self::METHOD_LEVEL, $className, $methodName); + } + + /** + * @param non-empty-string $operatingSystem + */ + public static function requiresOperatingSystemOnClass(string $operatingSystem): RequiresOperatingSystem + { + return new RequiresOperatingSystem(self::CLASS_LEVEL, $operatingSystem); + } + + /** + * @param non-empty-string $operatingSystem + */ + public static function requiresOperatingSystemOnMethod(string $operatingSystem): RequiresOperatingSystem + { + return new RequiresOperatingSystem(self::METHOD_LEVEL, $operatingSystem); + } + + /** + * @param non-empty-string $operatingSystemFamily + */ + public static function requiresOperatingSystemFamilyOnClass(string $operatingSystemFamily): RequiresOperatingSystemFamily + { + return new RequiresOperatingSystemFamily(self::CLASS_LEVEL, $operatingSystemFamily); + } + + /** + * @param non-empty-string $operatingSystemFamily + */ + public static function requiresOperatingSystemFamilyOnMethod(string $operatingSystemFamily): RequiresOperatingSystemFamily + { + return new RequiresOperatingSystemFamily(self::METHOD_LEVEL, $operatingSystemFamily); + } + + public static function requiresPhpOnClass(Requirement $versionRequirement): RequiresPhp + { + return new RequiresPhp(self::CLASS_LEVEL, $versionRequirement); + } + + public static function requiresPhpOnMethod(Requirement $versionRequirement): RequiresPhp + { + return new RequiresPhp(self::METHOD_LEVEL, $versionRequirement); + } + + /** + * @param non-empty-string $extension + */ + public static function requiresPhpExtensionOnClass(string $extension, ?Requirement $versionRequirement): RequiresPhpExtension + { + return new RequiresPhpExtension(self::CLASS_LEVEL, $extension, $versionRequirement); + } + + /** + * @param non-empty-string $extension + */ + public static function requiresPhpExtensionOnMethod(string $extension, ?Requirement $versionRequirement): RequiresPhpExtension + { + return new RequiresPhpExtension(self::METHOD_LEVEL, $extension, $versionRequirement); + } + + public static function requiresPhpunitOnClass(Requirement $versionRequirement): RequiresPhpunit + { + return new RequiresPhpunit(self::CLASS_LEVEL, $versionRequirement); + } + + public static function requiresPhpunitOnMethod(Requirement $versionRequirement): RequiresPhpunit + { + return new RequiresPhpunit(self::METHOD_LEVEL, $versionRequirement); + } + + /** + * @param class-string $extensionClass + */ + public static function requiresPhpunitExtensionOnClass(string $extensionClass): RequiresPhpunitExtension + { + return new RequiresPhpunitExtension(self::CLASS_LEVEL, $extensionClass); + } + + /** + * @param class-string $extensionClass + */ + public static function requiresPhpunitExtensionOnMethod(string $extensionClass): RequiresPhpunitExtension + { + return new RequiresPhpunitExtension(self::METHOD_LEVEL, $extensionClass); + } + + public static function requiresEnvironmentVariableOnClass(string $environmentVariableName, null|string $value): RequiresEnvironmentVariable + { + return new RequiresEnvironmentVariable(self::CLASS_LEVEL, $environmentVariableName, $value); + } + + public static function requiresEnvironmentVariableOnMethod(string $environmentVariableName, null|string $value): RequiresEnvironmentVariable + { + return new RequiresEnvironmentVariable(self::METHOD_LEVEL, $environmentVariableName, $value); + } + + public static function withEnvironmentVariableOnClass(string $environmentVariableName, null|string $value): WithEnvironmentVariable + { + return new WithEnvironmentVariable(self::CLASS_LEVEL, $environmentVariableName, $value); + } + + public static function withEnvironmentVariableOnMethod(string $environmentVariableName, null|string $value): WithEnvironmentVariable + { + return new WithEnvironmentVariable(self::METHOD_LEVEL, $environmentVariableName, $value); + } + + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public static function requiresSettingOnClass(string $setting, string $value): RequiresSetting + { + return new RequiresSetting(self::CLASS_LEVEL, $setting, $value); + } + + /** + * @param non-empty-string $setting + * @param non-empty-string $value + */ + public static function requiresSettingOnMethod(string $setting, string $value): RequiresSetting + { + return new RequiresSetting(self::METHOD_LEVEL, $setting, $value); + } + + public static function runTestsInSeparateProcesses(): RunTestsInSeparateProcesses + { + return new RunTestsInSeparateProcesses(self::CLASS_LEVEL); + } + + public static function runInSeparateProcess(): RunInSeparateProcess + { + return new RunInSeparateProcess(self::METHOD_LEVEL); + } + + public static function test(): Test + { + return new Test(self::METHOD_LEVEL); + } + + /** + * @param non-empty-string $text + */ + public static function testDoxOnClass(string $text): TestDox + { + return new TestDox(self::CLASS_LEVEL, $text); + } + + /** + * @param non-empty-string $text + */ + public static function testDoxOnMethod(string $text): TestDox + { + return new TestDox(self::METHOD_LEVEL, $text); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function testDoxFormatter(string $className, string $methodName): TestDoxFormatter + { + return new TestDoxFormatter(self::METHOD_LEVEL, $className, $methodName); + } + + /** + * @param ?non-empty-string $name + */ + public static function testWith(mixed $data, ?string $name = null): TestWith + { + return new TestWith(self::METHOD_LEVEL, $data, $name); + } + + /** + * @param non-empty-string $namespace + */ + public static function usesNamespace(string $namespace): UsesNamespace + { + return new UsesNamespace(self::CLASS_LEVEL, $namespace); + } + + /** + * @param class-string $className + */ + public static function usesClass(string $className): UsesClass + { + return new UsesClass(self::CLASS_LEVEL, $className); + } + + /** + * @param class-string $className + */ + public static function usesClassesThatExtendClass(string $className): UsesClassesThatExtendClass + { + return new UsesClassesThatExtendClass(self::CLASS_LEVEL, $className); + } + + /** + * @param class-string $interfaceName + */ + public static function usesClassesThatImplementInterface(string $interfaceName): UsesClassesThatImplementInterface + { + return new UsesClassesThatImplementInterface(self::CLASS_LEVEL, $interfaceName); + } + + /** + * @param trait-string $traitName + */ + public static function usesTrait(string $traitName): UsesTrait + { + return new UsesTrait(self::CLASS_LEVEL, $traitName); + } + + /** + * @param non-empty-string $functionName + */ + public static function usesFunction(string $functionName): UsesFunction + { + return new UsesFunction(self::CLASS_LEVEL, $functionName); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public static function usesMethod(string $className, string $methodName): UsesMethod + { + return new UsesMethod(self::CLASS_LEVEL, $className, $methodName); + } + + public static function withoutErrorHandler(): WithoutErrorHandler + { + return new WithoutErrorHandler(self::METHOD_LEVEL); + } + + /** + * @param null|non-empty-string $messagePattern + */ + public static function ignorePhpunitWarnings(?string $messagePattern): IgnorePhpunitWarnings + { + return new IgnorePhpunitWarnings(self::METHOD_LEVEL, $messagePattern); + } + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level) + { + $this->level = $level; + } + + public function isClassLevel(): bool + { + return $this->level === self::CLASS_LEVEL; + } + + public function isMethodLevel(): bool + { + return $this->level === self::METHOD_LEVEL; + } + + /** + * @phpstan-assert-if-true After $this + */ + public function isAfter(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true AfterClass $this + */ + public function isAfterClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true AllowMockObjectsWithoutExpectations $this + */ + public function isAllowMockObjectsWithoutExpectations(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true BackupGlobals $this + */ + public function isBackupGlobals(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true BackupStaticProperties $this + */ + public function isBackupStaticProperties(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true BeforeClass $this + */ + public function isBeforeClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Before $this + */ + public function isBefore(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversNamespace $this + */ + public function isCoversNamespace(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversClass $this + */ + public function isCoversClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversClassesThatExtendClass $this + */ + public function isCoversClassesThatExtendClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversClassesThatImplementInterface $this + */ + public function isCoversClassesThatImplementInterface(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversTrait $this + */ + public function isCoversTrait(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversFunction $this + */ + public function isCoversFunction(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversMethod $this + */ + public function isCoversMethod(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true CoversNothing $this + */ + public function isCoversNothing(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DataProvider $this + */ + public function isDataProvider(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DependsOnClass $this + */ + public function isDependsOnClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DependsOnMethod $this + */ + public function isDependsOnMethod(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DisableReturnValueGenerationForTestDoubles $this + */ + public function isDisableReturnValueGenerationForTestDoubles(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true DoesNotPerformAssertions $this + */ + public function isDoesNotPerformAssertions(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true ExcludeGlobalVariableFromBackup $this + */ + public function isExcludeGlobalVariableFromBackup(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true ExcludeStaticPropertyFromBackup $this + */ + public function isExcludeStaticPropertyFromBackup(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Group $this + */ + public function isGroup(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true IgnoreDeprecations $this + */ + public function isIgnoreDeprecations(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true IgnorePhpunitDeprecations $this + * + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function isIgnorePhpunitDeprecations(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RunInSeparateProcess $this + */ + public function isRunInSeparateProcess(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RunTestsInSeparateProcesses $this + */ + public function isRunTestsInSeparateProcesses(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true Test $this + */ + public function isTest(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true PreCondition $this + */ + public function isPreCondition(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true PostCondition $this + */ + public function isPostCondition(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true PreserveGlobalState $this + */ + public function isPreserveGlobalState(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresMethod $this + */ + public function isRequiresMethod(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresFunction $this + */ + public function isRequiresFunction(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresOperatingSystem $this + */ + public function isRequiresOperatingSystem(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresOperatingSystemFamily $this + */ + public function isRequiresOperatingSystemFamily(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresPhp $this + */ + public function isRequiresPhp(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresPhpExtension $this + */ + public function isRequiresPhpExtension(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresPhpunit $this + */ + public function isRequiresPhpunit(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresPhpunitExtension $this + */ + public function isRequiresPhpunitExtension(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresEnvironmentVariable $this + */ + public function isRequiresEnvironmentVariable(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true WithEnvironmentVariable $this + */ + public function isWithEnvironmentVariable(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true RequiresSetting $this + */ + public function isRequiresSetting(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true TestDox $this + */ + public function isTestDox(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true TestDoxFormatter $this + */ + public function isTestDoxFormatter(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true TestWith $this + */ + public function isTestWith(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesNamespace $this + */ + public function isUsesNamespace(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesClass $this + */ + public function isUsesClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesClassesThatExtendClass $this + */ + public function isUsesClassesThatExtendClass(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesClassesThatImplementInterface $this + */ + public function isUsesClassesThatImplementInterface(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesTrait $this + */ + public function isUsesTrait(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesFunction $this + */ + public function isUsesFunction(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true UsesMethod $this + */ + public function isUsesMethod(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true WithoutErrorHandler $this + */ + public function isWithoutErrorHandler(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true IgnorePhpunitWarnings $this + */ + public function isIgnorePhpunitWarnings(): bool + { + return false; + } +} diff --git a/src/Metadata/MetadataCollection.php b/src/Metadata/MetadataCollection.php new file mode 100644 index 00000000000..a9244a4d89c --- /dev/null +++ b/src/Metadata/MetadataCollection.php @@ -0,0 +1,663 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use function array_filter; +use function array_merge; +use function count; +use Countable; +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MetadataCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $metadata; + + /** + * @param list $metadata + */ + public static function fromArray(array $metadata): self + { + return new self(...$metadata); + } + + private function __construct(Metadata ...$metadata) + { + $this->metadata = $metadata; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->metadata; + } + + public function count(): int + { + return count($this->metadata); + } + + /** + * @phpstan-assert-if-true 0 $this->count() + * @phpstan-assert-if-true array{} $this->asArray() + */ + public function isEmpty(): bool + { + return $this->count() === 0; + } + + /** + * @phpstan-assert-if-true positive-int $this->count() + * @phpstan-assert-if-true non-empty-list $this->asArray() + */ + public function isNotEmpty(): bool + { + return $this->count() > 0; + } + + public function getIterator(): MetadataCollectionIterator + { + return new MetadataCollectionIterator($this); + } + + public function mergeWith(self $other): self + { + return new self( + ...array_merge( + $this->asArray(), + $other->asArray(), + ), + ); + } + + public function isClassLevel(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isClassLevel(), + ), + ); + } + + public function isMethodLevel(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isMethodLevel(), + ), + ); + } + + public function isAfter(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isAfter(), + ), + ); + } + + public function isAfterClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isAfterClass(), + ), + ); + } + + public function isAllowMockObjectsWithoutExpectations(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isAllowMockObjectsWithoutExpectations(), + ), + ); + } + + public function isBackupGlobals(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isBackupGlobals(), + ), + ); + } + + public function isBackupStaticProperties(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isBackupStaticProperties(), + ), + ); + } + + public function isBeforeClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isBeforeClass(), + ), + ); + } + + public function isBefore(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isBefore(), + ), + ); + } + + public function isCoversNamespace(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversNamespace(), + ), + ); + } + + public function isCoversClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversClass(), + ), + ); + } + + public function isCoversClassesThatExtendClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversClassesThatExtendClass(), + ), + ); + } + + public function isCoversClassesThatImplementInterface(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversClassesThatImplementInterface(), + ), + ); + } + + public function isCoversTrait(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversTrait(), + ), + ); + } + + public function isCoversFunction(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversFunction(), + ), + ); + } + + public function isCoversMethod(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversMethod(), + ), + ); + } + + public function isExcludeGlobalVariableFromBackup(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isExcludeGlobalVariableFromBackup(), + ), + ); + } + + public function isExcludeStaticPropertyFromBackup(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isExcludeStaticPropertyFromBackup(), + ), + ); + } + + public function isCoversNothing(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isCoversNothing(), + ), + ); + } + + public function isDataProvider(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDataProvider(), + ), + ); + } + + public function isDepends(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDependsOnClass() || $metadata->isDependsOnMethod(), + ), + ); + } + + public function isDependsOnClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDependsOnClass(), + ), + ); + } + + public function isDependsOnMethod(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDependsOnMethod(), + ), + ); + } + + public function isDisableReturnValueGenerationForTestDoubles(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDisableReturnValueGenerationForTestDoubles(), + ), + ); + } + + public function isDoesNotPerformAssertions(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isDoesNotPerformAssertions(), + ), + ); + } + + public function isGroup(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isGroup(), + ), + ); + } + + public function isIgnoreDeprecations(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isIgnoreDeprecations(), + ), + ); + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function isIgnorePhpunitDeprecations(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isIgnorePhpunitDeprecations(), + ), + ); + } + + public function isIgnorePhpunitWarnings(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isIgnorePhpunitWarnings(), + ), + ); + } + + public function isRunInSeparateProcess(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRunInSeparateProcess(), + ), + ); + } + + public function isRunTestsInSeparateProcesses(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRunTestsInSeparateProcesses(), + ), + ); + } + + public function isTest(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isTest(), + ), + ); + } + + public function isPreCondition(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isPreCondition(), + ), + ); + } + + public function isPostCondition(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isPostCondition(), + ), + ); + } + + public function isPreserveGlobalState(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isPreserveGlobalState(), + ), + ); + } + + public function isRequiresMethod(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresMethod(), + ), + ); + } + + public function isRequiresFunction(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresFunction(), + ), + ); + } + + public function isRequiresOperatingSystem(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresOperatingSystem(), + ), + ); + } + + public function isRequiresOperatingSystemFamily(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresOperatingSystemFamily(), + ), + ); + } + + public function isRequiresPhp(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresPhp(), + ), + ); + } + + public function isRequiresPhpExtension(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresPhpExtension(), + ), + ); + } + + public function isRequiresPhpunit(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresPhpunit(), + ), + ); + } + + public function isRequiresPhpunitExtension(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresPhpunitExtension(), + ), + ); + } + + public function isRequiresEnvironmentVariable(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresEnvironmentVariable(), + ), + ); + } + + public function isWithEnvironmentVariable(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isWithEnvironmentVariable(), + ), + ); + } + + public function isRequiresSetting(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isRequiresSetting(), + ), + ); + } + + public function isTestDox(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isTestDox(), + ), + ); + } + + public function isTestDoxFormatter(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isTestDoxFormatter(), + ), + ); + } + + public function isTestWith(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isTestWith(), + ), + ); + } + + public function isUsesNamespace(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesNamespace(), + ), + ); + } + + public function isUsesClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesClass(), + ), + ); + } + + public function isUsesClassesThatExtendClass(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesClassesThatExtendClass(), + ), + ); + } + + public function isUsesClassesThatImplementInterface(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesClassesThatImplementInterface(), + ), + ); + } + + public function isUsesTrait(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesTrait(), + ), + ); + } + + public function isUsesFunction(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesFunction(), + ), + ); + } + + public function isUsesMethod(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isUsesMethod(), + ), + ); + } + + public function isWithoutErrorHandler(): self + { + return new self( + ...array_filter( + $this->metadata, + static fn (Metadata $metadata): bool => $metadata->isWithoutErrorHandler(), + ), + ); + } +} diff --git a/src/Metadata/MetadataCollectionIterator.php b/src/Metadata/MetadataCollectionIterator.php new file mode 100644 index 00000000000..bfe398999e3 --- /dev/null +++ b/src/Metadata/MetadataCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use function count; +use Iterator; + +/** + * @template-implements Iterator + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class MetadataCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $metadata; + private int $position = 0; + + public function __construct(MetadataCollection $metadata) + { + $this->metadata = $metadata->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->metadata); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Metadata + { + return $this->metadata[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/Metadata/Parser/AttributeParser.php b/src/Metadata/Parser/AttributeParser.php new file mode 100644 index 00000000000..f6de163bb1d --- /dev/null +++ b/src/Metadata/Parser/AttributeParser.php @@ -0,0 +1,1020 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use const JSON_THROW_ON_ERROR; +use function assert; +use function class_exists; +use function is_numeric; +use function json_decode; +use function method_exists; +use function sprintf; +use function str_starts_with; +use function strtolower; +use function trim; +use Error; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\CoversClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversNamespace; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\Attributes\DependsExternalUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsExternalUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsUsingShallowClone; +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup; +use PHPUnit\Framework\Attributes\ExcludeStaticPropertyFromBackup; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\Attributes\IgnorePhpunitWarnings; +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\Attributes\RequiresFunction; +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RequiresPhpunitExtension; +use PHPUnit\Framework\Attributes\RequiresSetting; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\Attributes\TestDoxFormatterExternal; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\Attributes\UsesClassesThatExtendClass; +use PHPUnit\Framework\Attributes\UsesClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\Attributes\UsesMethod; +use PHPUnit\Framework\Attributes\UsesNamespace; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Metadata\InvalidAttributeException; +use PHPUnit\Metadata\Metadata; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\Metadata\Version\Requirement; +use ReflectionClass; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AttributeParser implements Parser +{ + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection + { + assert(class_exists($className)); + + $reflector = new ReflectionClass($className); + $result = []; + + $small = false; + $medium = false; + $large = false; + + foreach ($reflector->getAttributes() as $attribute) { + if (!str_starts_with($attribute->getName(), 'PHPUnit\\Framework\\Attributes\\')) { + continue; + } + + if (!class_exists($attribute->getName())) { + continue; + } + + try { + $attributeInstance = $attribute->newInstance(); + } catch (Error $e) { + throw new InvalidAttributeException( + $attribute->getName(), + 'class ' . $className, + $reflector->getFileName(), + $reflector->getStartLine(), + $e->getMessage(), + ); + } + + switch ($attribute->getName()) { + case AllowMockObjectsWithoutExpectations::class: + assert($attributeInstance instanceof AllowMockObjectsWithoutExpectations); + + $result[] = Metadata::allowMockObjectsWithoutExpectationsOnClass(); + + break; + + case BackupGlobals::class: + assert($attributeInstance instanceof BackupGlobals); + + $result[] = Metadata::backupGlobalsOnClass($attributeInstance->enabled()); + + break; + + case BackupStaticProperties::class: + assert($attributeInstance instanceof BackupStaticProperties); + + $result[] = Metadata::backupStaticPropertiesOnClass($attributeInstance->enabled()); + + break; + + case CoversNamespace::class: + assert($attributeInstance instanceof CoversNamespace); + + $result[] = Metadata::coversNamespace($attributeInstance->namespace()); + + break; + + case CoversClass::class: + assert($attributeInstance instanceof CoversClass); + + $result[] = Metadata::coversClass($attributeInstance->className()); + + break; + + case CoversClassesThatExtendClass::class: + assert($attributeInstance instanceof CoversClassesThatExtendClass); + + $result[] = Metadata::coversClassesThatExtendClass($attributeInstance->className()); + + break; + + case CoversClassesThatImplementInterface::class: + assert($attributeInstance instanceof CoversClassesThatImplementInterface); + + $result[] = Metadata::coversClassesThatImplementInterface($attributeInstance->interfaceName()); + + break; + + case CoversTrait::class: + assert($attributeInstance instanceof CoversTrait); + + $result[] = Metadata::coversTrait($attributeInstance->traitName()); + + break; + + case CoversFunction::class: + assert($attributeInstance instanceof CoversFunction); + + $result[] = Metadata::coversFunction($attributeInstance->functionName()); + + break; + + case CoversMethod::class: + assert($attributeInstance instanceof CoversMethod); + + $result[] = Metadata::coversMethod( + $attributeInstance->className(), + $attributeInstance->methodName(), + ); + + break; + + case CoversNothing::class: + $result[] = Metadata::coversNothingOnClass(); + + break; + + case DisableReturnValueGenerationForTestDoubles::class: + $result[] = Metadata::disableReturnValueGenerationForTestDoubles(); + + break; + + case DoesNotPerformAssertions::class: + $result[] = Metadata::doesNotPerformAssertionsOnClass(); + + break; + + case ExcludeGlobalVariableFromBackup::class: + assert($attributeInstance instanceof ExcludeGlobalVariableFromBackup); + + $result[] = Metadata::excludeGlobalVariableFromBackupOnClass($attributeInstance->globalVariableName()); + + break; + + case ExcludeStaticPropertyFromBackup::class: + assert($attributeInstance instanceof ExcludeStaticPropertyFromBackup); + + $result[] = Metadata::excludeStaticPropertyFromBackupOnClass( + $attributeInstance->className(), + $attributeInstance->propertyName(), + ); + + break; + + case Group::class: + assert($attributeInstance instanceof Group); + + if (!$this->isSizeGroup($attributeInstance->name(), $className)) { + $result[] = Metadata::groupOnClass($attributeInstance->name()); + } + + break; + + case Small::class: + if (!$medium && !$large) { + $result[] = Metadata::groupOnClass('small'); + + $small = true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '#[Small] cannot be combined with #[Medium] or #[Large] for %s', + $this->testAsString($className), + ), + ); + } + + break; + + case Medium::class: + if (!$small && !$large) { + $result[] = Metadata::groupOnClass('medium'); + + $medium = true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '#[Medium] cannot be combined with #[Small] or #[Large] for %s', + $this->testAsString($className), + ), + ); + } + + break; + + case Large::class: + if (!$small && !$medium) { + $result[] = Metadata::groupOnClass('large'); + + $large = true; + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '#[Large] cannot be combined with #[Small] or #[Medium] for %s', + $this->testAsString($className), + ), + ); + } + + break; + + case IgnoreDeprecations::class: + assert($attributeInstance instanceof IgnoreDeprecations); + + $result[] = Metadata::ignoreDeprecationsOnClass($attributeInstance->messagePattern()); + + break; + + case IgnorePhpunitDeprecations::class: + assert($attributeInstance instanceof IgnorePhpunitDeprecations); + + $result[] = Metadata::ignorePhpunitDeprecationsOnClass(); + + break; + + case PreserveGlobalState::class: + assert($attributeInstance instanceof PreserveGlobalState); + + $result[] = Metadata::preserveGlobalStateOnClass($attributeInstance->enabled()); + + break; + + case RequiresMethod::class: + assert($attributeInstance instanceof RequiresMethod); + + $result[] = Metadata::requiresMethodOnClass( + $attributeInstance->className(), + $attributeInstance->methodName(), + ); + + break; + + case RequiresFunction::class: + assert($attributeInstance instanceof RequiresFunction); + + $result[] = Metadata::requiresFunctionOnClass($attributeInstance->functionName()); + + break; + + case RequiresOperatingSystem::class: + assert($attributeInstance instanceof RequiresOperatingSystem); + + $result[] = Metadata::requiresOperatingSystemOnClass($attributeInstance->regularExpression()); + + break; + + case RequiresOperatingSystemFamily::class: + assert($attributeInstance instanceof RequiresOperatingSystemFamily); + + $result[] = Metadata::requiresOperatingSystemFamilyOnClass($attributeInstance->operatingSystemFamily()); + + break; + + case RequiresPhp::class: + assert($attributeInstance instanceof RequiresPhp); + + $requirement = $this->requirement( + $attributeInstance->versionRequirement(), + $className, + ); + + if ($requirement !== null) { + $result[] = Metadata::requiresPhpOnClass($requirement); + } + + break; + + case RequiresPhpExtension::class: + assert($attributeInstance instanceof RequiresPhpExtension); + + $versionConstraint = null; + $versionRequirement = $attributeInstance->versionRequirement(); + + if ($versionRequirement !== null) { + $versionConstraint = $this->requirement( + $versionRequirement, + $className, + ); + } + + $result[] = Metadata::requiresPhpExtensionOnClass( + $attributeInstance->extension(), + $versionConstraint, + ); + + break; + + case RequiresPhpunit::class: + assert($attributeInstance instanceof RequiresPhpunit); + + $requirement = $this->requirement( + $attributeInstance->versionRequirement(), + $className, + ); + + if ($requirement !== null) { + $result[] = Metadata::requiresPhpunitOnClass($requirement); + } + + break; + + case RequiresPhpunitExtension::class: + assert($attributeInstance instanceof RequiresPhpunitExtension); + + $result[] = Metadata::requiresPhpunitExtensionOnClass( + $attributeInstance->extensionClass(), + ); + + break; + + case RequiresEnvironmentVariable::class: + assert($attributeInstance instanceof RequiresEnvironmentVariable); + + $result[] = Metadata::requiresEnvironmentVariableOnClass( + $attributeInstance->environmentVariableName(), + $attributeInstance->value(), + ); + + break; + + case WithEnvironmentVariable::class: + assert($attributeInstance instanceof WithEnvironmentVariable); + + $result[] = Metadata::withEnvironmentVariableOnClass( + $attributeInstance->environmentVariableName(), + $attributeInstance->value(), + ); + + break; + + case RequiresSetting::class: + assert($attributeInstance instanceof RequiresSetting); + + $result[] = Metadata::requiresSettingOnClass( + $attributeInstance->setting(), + $attributeInstance->value(), + ); + + break; + + case RunTestsInSeparateProcesses::class: + $result[] = Metadata::runTestsInSeparateProcesses(); + + break; + + case TestDox::class: + assert($attributeInstance instanceof TestDox); + + $result[] = Metadata::testDoxOnClass($attributeInstance->text()); + + break; + + case Ticket::class: + assert($attributeInstance instanceof Ticket); + + $result[] = Metadata::groupOnClass($attributeInstance->text()); + + break; + + case UsesNamespace::class: + assert($attributeInstance instanceof UsesNamespace); + + $result[] = Metadata::usesNamespace($attributeInstance->namespace()); + + break; + + case UsesClass::class: + assert($attributeInstance instanceof UsesClass); + + $result[] = Metadata::usesClass($attributeInstance->className()); + + break; + + case UsesClassesThatExtendClass::class: + assert($attributeInstance instanceof UsesClassesThatExtendClass); + + $result[] = Metadata::usesClassesThatExtendClass($attributeInstance->className()); + + break; + + case UsesClassesThatImplementInterface::class: + assert($attributeInstance instanceof UsesClassesThatImplementInterface); + + $result[] = Metadata::usesClassesThatImplementInterface($attributeInstance->interfaceName()); + + break; + + case UsesTrait::class: + assert($attributeInstance instanceof UsesTrait); + + $result[] = Metadata::usesTrait($attributeInstance->traitName()); + + break; + + case UsesFunction::class: + assert($attributeInstance instanceof UsesFunction); + + $result[] = Metadata::usesFunction($attributeInstance->functionName()); + + break; + + case UsesMethod::class: + assert($attributeInstance instanceof UsesMethod); + + $result[] = Metadata::usesMethod( + $attributeInstance->className(), + $attributeInstance->methodName(), + ); + + break; + } + } + + return MetadataCollection::fromArray($result); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection + { + assert(class_exists($className)); + assert(method_exists($className, $methodName)); + + $reflector = new ReflectionMethod($className, $methodName); + $result = []; + + foreach ($reflector->getAttributes() as $attribute) { + if (!str_starts_with($attribute->getName(), 'PHPUnit\\Framework\\Attributes\\')) { + continue; + } + + if (!class_exists($attribute->getName())) { + continue; + } + + try { + $attributeInstance = $attribute->newInstance(); + } catch (Error $e) { + throw new InvalidAttributeException( + $attribute->getName(), + 'method ' . $className . '::' . $methodName . '()', + $reflector->getFileName(), + $reflector->getStartLine(), + $e->getMessage(), + ); + } + + switch ($attribute->getName()) { + case After::class: + assert($attributeInstance instanceof After); + + $result[] = Metadata::after($attributeInstance->priority()); + + break; + + case AfterClass::class: + assert($attributeInstance instanceof AfterClass); + + $result[] = Metadata::afterClass($attributeInstance->priority()); + + break; + + case AllowMockObjectsWithoutExpectations::class: + assert($attributeInstance instanceof AllowMockObjectsWithoutExpectations); + + $result[] = Metadata::allowMockObjectsWithoutExpectationsOnMethod(); + + break; + + case BackupGlobals::class: + assert($attributeInstance instanceof BackupGlobals); + + $result[] = Metadata::backupGlobalsOnMethod($attributeInstance->enabled()); + + break; + + case BackupStaticProperties::class: + assert($attributeInstance instanceof BackupStaticProperties); + + $result[] = Metadata::backupStaticPropertiesOnMethod($attributeInstance->enabled()); + + break; + + case Before::class: + assert($attributeInstance instanceof Before); + + $result[] = Metadata::before($attributeInstance->priority()); + + break; + + case BeforeClass::class: + assert($attributeInstance instanceof BeforeClass); + + $result[] = Metadata::beforeClass($attributeInstance->priority()); + + break; + + case CoversNothing::class: + $result[] = Metadata::coversNothingOnMethod(); + + break; + + case DataProvider::class: + assert($attributeInstance instanceof DataProvider); + + $result[] = Metadata::dataProvider($className, $attributeInstance->methodName(), $attributeInstance->validateArgumentCount()); + + break; + + case DataProviderExternal::class: + assert($attributeInstance instanceof DataProviderExternal); + + $result[] = Metadata::dataProvider($attributeInstance->className(), $attributeInstance->methodName(), $attributeInstance->validateArgumentCount()); + + break; + + case Depends::class: + assert($attributeInstance instanceof Depends); + + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), false, false); + + break; + + case DependsUsingDeepClone::class: + assert($attributeInstance instanceof DependsUsingDeepClone); + + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), true, false); + + break; + + case DependsUsingShallowClone::class: + assert($attributeInstance instanceof DependsUsingShallowClone); + + $result[] = Metadata::dependsOnMethod($className, $attributeInstance->methodName(), false, true); + + break; + + case DependsExternal::class: + assert($attributeInstance instanceof DependsExternal); + + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), false, false); + + break; + + case DependsExternalUsingDeepClone::class: + assert($attributeInstance instanceof DependsExternalUsingDeepClone); + + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), true, false); + + break; + + case DependsExternalUsingShallowClone::class: + assert($attributeInstance instanceof DependsExternalUsingShallowClone); + + $result[] = Metadata::dependsOnMethod($attributeInstance->className(), $attributeInstance->methodName(), false, true); + + break; + + case DependsOnClass::class: + assert($attributeInstance instanceof DependsOnClass); + + $result[] = Metadata::dependsOnClass($attributeInstance->className(), false, false); + + break; + + case DependsOnClassUsingDeepClone::class: + assert($attributeInstance instanceof DependsOnClassUsingDeepClone); + + $result[] = Metadata::dependsOnClass($attributeInstance->className(), true, false); + + break; + + case DependsOnClassUsingShallowClone::class: + assert($attributeInstance instanceof DependsOnClassUsingShallowClone); + + $result[] = Metadata::dependsOnClass($attributeInstance->className(), false, true); + + break; + + case DoesNotPerformAssertions::class: + assert($attributeInstance instanceof DoesNotPerformAssertions); + + $result[] = Metadata::doesNotPerformAssertionsOnMethod(); + + break; + + case ExcludeGlobalVariableFromBackup::class: + assert($attributeInstance instanceof ExcludeGlobalVariableFromBackup); + + $result[] = Metadata::excludeGlobalVariableFromBackupOnMethod($attributeInstance->globalVariableName()); + + break; + + case ExcludeStaticPropertyFromBackup::class: + assert($attributeInstance instanceof ExcludeStaticPropertyFromBackup); + + $result[] = Metadata::excludeStaticPropertyFromBackupOnMethod( + $attributeInstance->className(), + $attributeInstance->propertyName(), + ); + + break; + + case Group::class: + assert($attributeInstance instanceof Group); + + if (!$this->isSizeGroup($attributeInstance->name(), $className, $methodName)) { + $result[] = Metadata::groupOnMethod($attributeInstance->name()); + } + + break; + + case IgnoreDeprecations::class: + assert($attributeInstance instanceof IgnoreDeprecations); + + $result[] = Metadata::ignoreDeprecationsOnMethod($attributeInstance->messagePattern()); + + break; + + case IgnorePhpunitDeprecations::class: + assert($attributeInstance instanceof IgnorePhpunitDeprecations); + + $result[] = Metadata::ignorePhpunitDeprecationsOnMethod(); + + break; + + case PostCondition::class: + assert($attributeInstance instanceof PostCondition); + + $result[] = Metadata::postCondition($attributeInstance->priority()); + + break; + + case PreCondition::class: + assert($attributeInstance instanceof PreCondition); + + $result[] = Metadata::preCondition($attributeInstance->priority()); + + break; + + case PreserveGlobalState::class: + assert($attributeInstance instanceof PreserveGlobalState); + + $result[] = Metadata::preserveGlobalStateOnMethod($attributeInstance->enabled()); + + break; + + case RequiresMethod::class: + assert($attributeInstance instanceof RequiresMethod); + + $result[] = Metadata::requiresMethodOnMethod( + $attributeInstance->className(), + $attributeInstance->methodName(), + ); + + break; + + case RequiresFunction::class: + assert($attributeInstance instanceof RequiresFunction); + + $result[] = Metadata::requiresFunctionOnMethod($attributeInstance->functionName()); + + break; + + case RequiresOperatingSystem::class: + assert($attributeInstance instanceof RequiresOperatingSystem); + + $result[] = Metadata::requiresOperatingSystemOnMethod($attributeInstance->regularExpression()); + + break; + + case RequiresOperatingSystemFamily::class: + assert($attributeInstance instanceof RequiresOperatingSystemFamily); + + $result[] = Metadata::requiresOperatingSystemFamilyOnMethod($attributeInstance->operatingSystemFamily()); + + break; + + case RequiresPhp::class: + assert($attributeInstance instanceof RequiresPhp); + + $requirement = $this->requirement( + $attributeInstance->versionRequirement(), + $className, + $methodName, + ); + + if ($requirement !== null) { + $result[] = Metadata::requiresPhpOnMethod($requirement); + } + + break; + + case RequiresPhpExtension::class: + assert($attributeInstance instanceof RequiresPhpExtension); + + $versionConstraint = null; + $versionRequirement = $attributeInstance->versionRequirement(); + + if ($versionRequirement !== null) { + $versionConstraint = $this->requirement( + $versionRequirement, + $className, + $methodName, + ); + } + + $result[] = Metadata::requiresPhpExtensionOnMethod( + $attributeInstance->extension(), + $versionConstraint, + ); + + break; + + case RequiresPhpunit::class: + assert($attributeInstance instanceof RequiresPhpunit); + + $requirement = $this->requirement( + $attributeInstance->versionRequirement(), + $className, + $methodName, + ); + + if ($requirement !== null) { + $result[] = Metadata::requiresPhpunitOnMethod($requirement); + } + + break; + + case RequiresPhpunitExtension::class: + assert($attributeInstance instanceof RequiresPhpunitExtension); + + $result[] = Metadata::requiresPhpunitExtensionOnMethod( + $attributeInstance->extensionClass(), + ); + + break; + + case RequiresEnvironmentVariable::class: + assert($attributeInstance instanceof RequiresEnvironmentVariable); + + $result[] = Metadata::requiresEnvironmentVariableOnMethod( + $attributeInstance->environmentVariableName(), + $attributeInstance->value(), + ); + + break; + + case WithEnvironmentVariable::class: + assert($attributeInstance instanceof WithEnvironmentVariable); + + $result[] = Metadata::withEnvironmentVariableOnMethod( + $attributeInstance->environmentVariableName(), + $attributeInstance->value(), + ); + + break; + + case RequiresSetting::class: + assert($attributeInstance instanceof RequiresSetting); + + $result[] = Metadata::requiresSettingOnMethod( + $attributeInstance->setting(), + $attributeInstance->value(), + ); + + break; + + case RunInSeparateProcess::class: + $result[] = Metadata::runInSeparateProcess(); + + break; + + case Test::class: + $result[] = Metadata::test(); + + break; + + case TestDox::class: + assert($attributeInstance instanceof TestDox); + + $result[] = Metadata::testDoxOnMethod($attributeInstance->text()); + + break; + + case TestDoxFormatter::class: + assert($attributeInstance instanceof TestDoxFormatter); + + $result[] = Metadata::testDoxFormatter($className, $attributeInstance->methodName()); + + break; + + case TestDoxFormatterExternal::class: + assert($attributeInstance instanceof TestDoxFormatterExternal); + + $result[] = Metadata::testDoxFormatter($attributeInstance->className(), $attributeInstance->methodName()); + + break; + + case TestWith::class: + assert($attributeInstance instanceof TestWith); + + $result[] = Metadata::testWith($attributeInstance->data(), $attributeInstance->name()); + + break; + + case TestWithJson::class: + assert($attributeInstance instanceof TestWithJson); + + $result[] = Metadata::testWith( + json_decode($attributeInstance->json(), true, 512, JSON_THROW_ON_ERROR), + $attributeInstance->name(), + ); + + break; + + case Ticket::class: + assert($attributeInstance instanceof Ticket); + + $result[] = Metadata::groupOnMethod($attributeInstance->text()); + + break; + + case WithoutErrorHandler::class: + assert($attributeInstance instanceof WithoutErrorHandler); + + $result[] = Metadata::withoutErrorHandler(); + + break; + + case IgnorePhpunitWarnings::class: + assert($attributeInstance instanceof IgnorePhpunitWarnings); + + $result[] = Metadata::ignorePhpunitWarnings($attributeInstance->messagePattern()); + + break; + } + } + + return MetadataCollection::fromArray($result); + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection + { + return $this->forClass($className)->mergeWith( + $this->forMethod($className, $methodName), + ); + } + + /** + * @param non-empty-string $groupName + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + */ + private function isSizeGroup(string $groupName, string $testClassName, ?string $testMethodName = null): bool + { + $_groupName = strtolower(trim($groupName)); + + if ($_groupName !== 'small' && $_groupName !== 'medium' && $_groupName !== 'large') { + return false; + } + + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Group name "%s" is not allowed for %s', + $_groupName, + $this->testAsString($testClassName, $testMethodName), + ), + ); + + return true; + } + + /** + * @param non-empty-string $versionRequirement + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + */ + private function requirement(string $versionRequirement, string $testClassName, ?string $testMethodName = null): ?Requirement + { + if (is_numeric(trim($versionRequirement))) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Test %s has attribute with version constraint string argument without explicit version comparison operator ("%s"), version constraint is ignored', + $this->testAsString($testClassName, $testMethodName), + $versionRequirement, + ), + ); + + return null; + } + + return Requirement::from($versionRequirement); + } + + /** + * @param class-string $testClassName + * @param ?non-empty-string $testMethodName + * + * @return non-empty-string + */ + private function testAsString(string $testClassName, ?string $testMethodName = null): string + { + return sprintf( + '%s %s%s%s', + $testMethodName !== null ? 'method' : 'class', + $testClassName, + $testMethodName !== null ? '::' : '', + $testMethodName !== null ? $testMethodName : '', + ); + } +} diff --git a/src/Metadata/Parser/CachingParser.php b/src/Metadata/Parser/CachingParser.php new file mode 100644 index 00000000000..7c274c15e14 --- /dev/null +++ b/src/Metadata/Parser/CachingParser.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use function assert; +use function class_exists; +use function method_exists; +use PHPUnit\Metadata\MetadataCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CachingParser implements Parser +{ + private readonly Parser $reader; + + /** + * @var array + */ + private array $classCache = []; + + /** + * @var array + */ + private array $methodCache = []; + + /** + * @var array + */ + private array $classAndMethodCache = []; + + public function __construct(Parser $reader) + { + $this->reader = $reader; + } + + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection + { + assert(class_exists($className)); + + if (isset($this->classCache[$className])) { + return $this->classCache[$className]; + } + + $this->classCache[$className] = $this->reader->forClass($className); + + return $this->classCache[$className]; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection + { + assert(class_exists($className)); + assert(method_exists($className, $methodName)); + + $key = $className . '::' . $methodName; + + if (isset($this->methodCache[$key])) { + return $this->methodCache[$key]; + } + + $this->methodCache[$key] = $this->reader->forMethod($className, $methodName); + + return $this->methodCache[$key]; + } + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection + { + $key = $className . '::' . $methodName; + + if (isset($this->classAndMethodCache[$key])) { + return $this->classAndMethodCache[$key]; + } + + $this->classAndMethodCache[$key] = $this->forClass($className)->mergeWith( + $this->forMethod($className, $methodName), + ); + + return $this->classAndMethodCache[$key]; + } +} diff --git a/src/Metadata/Parser/Parser.php b/src/Metadata/Parser/Parser.php new file mode 100644 index 00000000000..edc2d87f473 --- /dev/null +++ b/src/Metadata/Parser/Parser.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use PHPUnit\Metadata\MetadataCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Parser +{ + /** + * @param class-string $className + */ + public function forClass(string $className): MetadataCollection; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forMethod(string $className, string $methodName): MetadataCollection; + + /** + * @param class-string $className + * @param non-empty-string $methodName + */ + public function forClassAndMethod(string $className, string $methodName): MetadataCollection; +} diff --git a/src/Metadata/Parser/Registry.php b/src/Metadata/Parser/Registry.php new file mode 100644 index 00000000000..0b30782ec09 --- /dev/null +++ b/src/Metadata/Parser/Registry.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +/** + * Attribute information is static within a single PHP process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Registry +{ + private static ?Parser $instance = null; + + public static function parser(): Parser + { + return self::$instance ?? self::$instance = self::build(); + } + + private static function build(): Parser + { + return new CachingParser(new AttributeParser); + } +} diff --git a/src/Metadata/PostCondition.php b/src/Metadata/PostCondition.php new file mode 100644 index 00000000000..d52ae0628bd --- /dev/null +++ b/src/Metadata/PostCondition.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PostCondition extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isPostCondition(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/PreCondition.php b/src/Metadata/PreCondition.php new file mode 100644 index 00000000000..9243122bcb6 --- /dev/null +++ b/src/Metadata/PreCondition.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreCondition extends Metadata +{ + private int $priority; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, int $priority) + { + parent::__construct($level); + + $this->priority = $priority; + } + + public function isPreCondition(): true + { + return true; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Metadata/PreserveGlobalState.php b/src/Metadata/PreserveGlobalState.php new file mode 100644 index 00000000000..f888119159c --- /dev/null +++ b/src/Metadata/PreserveGlobalState.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PreserveGlobalState extends Metadata +{ + private bool $enabled; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, bool $enabled) + { + parent::__construct($level); + + $this->enabled = $enabled; + } + + public function isPreserveGlobalState(): true + { + return true; + } + + public function enabled(): bool + { + return $this->enabled; + } +} diff --git a/src/Metadata/RequiresEnvironmentVariable.php b/src/Metadata/RequiresEnvironmentVariable.php new file mode 100644 index 00000000000..0888c296d33 --- /dev/null +++ b/src/Metadata/RequiresEnvironmentVariable.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresEnvironmentVariable extends Metadata +{ + private string $environmentVariableName; + private null|string $value; + + public function __construct(int $level, string $environmentVariableName, null|string $value) + { + parent::__construct($level); + + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + + public function isRequiresEnvironmentVariable(): true + { + return true; + } + + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + + public function value(): null|string + { + return $this->value; + } +} diff --git a/src/Metadata/RequiresFunction.php b/src/Metadata/RequiresFunction.php new file mode 100644 index 00000000000..f66c5180c47 --- /dev/null +++ b/src/Metadata/RequiresFunction.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresFunction extends Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param int<0, 1> $level + * @param non-empty-string $functionName + */ + protected function __construct(int $level, string $functionName) + { + parent::__construct($level); + + $this->functionName = $functionName; + } + + public function isRequiresFunction(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Metadata/RequiresMethod.php b/src/Metadata/RequiresMethod.php new file mode 100644 index 00000000000..2ad7fbb9abc --- /dev/null +++ b/src/Metadata/RequiresMethod.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresMethod extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + } + + public function isRequiresMethod(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Metadata/RequiresOperatingSystem.php b/src/Metadata/RequiresOperatingSystem.php new file mode 100644 index 00000000000..8719d296120 --- /dev/null +++ b/src/Metadata/RequiresOperatingSystem.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresOperatingSystem extends Metadata +{ + /** + * @var non-empty-string + */ + private string $operatingSystem; + + /** + * @param int<0, 1> $level + * @param non-empty-string $operatingSystem + */ + public function __construct(int $level, string $operatingSystem) + { + parent::__construct($level); + + $this->operatingSystem = $operatingSystem; + } + + public function isRequiresOperatingSystem(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function operatingSystem(): string + { + return $this->operatingSystem; + } +} diff --git a/src/Metadata/RequiresOperatingSystemFamily.php b/src/Metadata/RequiresOperatingSystemFamily.php new file mode 100644 index 00000000000..4481dcf8ce5 --- /dev/null +++ b/src/Metadata/RequiresOperatingSystemFamily.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresOperatingSystemFamily extends Metadata +{ + /** + * @var non-empty-string + */ + private string $operatingSystemFamily; + + /** + * @param int<0, 1> $level + * @param non-empty-string $operatingSystemFamily + */ + protected function __construct(int $level, string $operatingSystemFamily) + { + parent::__construct($level); + + $this->operatingSystemFamily = $operatingSystemFamily; + } + + public function isRequiresOperatingSystemFamily(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function operatingSystemFamily(): string + { + return $this->operatingSystemFamily; + } +} diff --git a/src/Metadata/RequiresPhp.php b/src/Metadata/RequiresPhp.php new file mode 100644 index 00000000000..c64a396281e --- /dev/null +++ b/src/Metadata/RequiresPhp.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhp extends Metadata +{ + private Requirement $versionRequirement; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, Requirement $versionRequirement) + { + parent::__construct($level); + + $this->versionRequirement = $versionRequirement; + } + + public function isRequiresPhp(): true + { + return true; + } + + public function versionRequirement(): Requirement + { + return $this->versionRequirement; + } +} diff --git a/src/Metadata/RequiresPhpExtension.php b/src/Metadata/RequiresPhpExtension.php new file mode 100644 index 00000000000..5c547ea9ec8 --- /dev/null +++ b/src/Metadata/RequiresPhpExtension.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpExtension extends Metadata +{ + /** + * @var non-empty-string + */ + private string $extension; + private ?Requirement $versionRequirement; + + /** + * @param int<0, 1> $level + * @param non-empty-string $extension + */ + protected function __construct(int $level, string $extension, ?Requirement $versionRequirement) + { + parent::__construct($level); + + $this->extension = $extension; + $this->versionRequirement = $versionRequirement; + } + + public function isRequiresPhpExtension(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function extension(): string + { + return $this->extension; + } + + /** + * @phpstan-assert-if-true !null $this->versionRequirement + */ + public function hasVersionRequirement(): bool + { + return $this->versionRequirement !== null; + } + + /** + * @throws NoVersionRequirementException + */ + public function versionRequirement(): Requirement + { + if ($this->versionRequirement === null) { + throw new NoVersionRequirementException; + } + + return $this->versionRequirement; + } +} diff --git a/src/Metadata/RequiresPhpunit.php b/src/Metadata/RequiresPhpunit.php new file mode 100644 index 00000000000..dc8ae80e2b4 --- /dev/null +++ b/src/Metadata/RequiresPhpunit.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Metadata\Version\Requirement; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpunit extends Metadata +{ + private Requirement $versionRequirement; + + /** + * @param int<0, 1> $level + */ + protected function __construct(int $level, Requirement $versionRequirement) + { + parent::__construct($level); + + $this->versionRequirement = $versionRequirement; + } + + public function isRequiresPhpunit(): true + { + return true; + } + + public function versionRequirement(): Requirement + { + return $this->versionRequirement; + } +} diff --git a/src/Metadata/RequiresPhpunitExtension.php b/src/Metadata/RequiresPhpunitExtension.php new file mode 100644 index 00000000000..726c3b961a8 --- /dev/null +++ b/src/Metadata/RequiresPhpunitExtension.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Runner\Extension\Extension; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresPhpunitExtension extends Metadata +{ + /** + * @var class-string + */ + private string $extensionClass; + + /** + * @param class-string $extensionClass + */ + public function __construct(int $level, string $extensionClass) + { + parent::__construct($level); + + $this->extensionClass = $extensionClass; + } + + public function isRequiresPhpunitExtension(): true + { + return true; + } + + /** + * @return class-string + */ + public function extensionClass(): string + { + return $this->extensionClass; + } +} diff --git a/src/Metadata/RequiresSetting.php b/src/Metadata/RequiresSetting.php new file mode 100644 index 00000000000..0d0b0230a40 --- /dev/null +++ b/src/Metadata/RequiresSetting.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RequiresSetting extends Metadata +{ + /** + * @var non-empty-string + */ + private string $setting; + + /** + * @var non-empty-string + */ + private string $value; + + /** + * @param int<0, 1> $level + * @param non-empty-string $setting + * @param non-empty-string $value + */ + protected function __construct(int $level, string $setting, string $value) + { + parent::__construct($level); + + $this->setting = $setting; + $this->value = $value; + } + + public function isRequiresSetting(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function setting(): string + { + return $this->setting; + } + + /** + * @return non-empty-string + */ + public function value(): string + { + return $this->value; + } +} diff --git a/src/Metadata/RunInSeparateProcess.php b/src/Metadata/RunInSeparateProcess.php new file mode 100644 index 00000000000..dc755219ce4 --- /dev/null +++ b/src/Metadata/RunInSeparateProcess.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RunInSeparateProcess extends Metadata +{ + public function isRunInSeparateProcess(): true + { + return true; + } +} diff --git a/src/Metadata/RunTestsInSeparateProcesses.php b/src/Metadata/RunTestsInSeparateProcesses.php new file mode 100644 index 00000000000..3a544a792c8 --- /dev/null +++ b/src/Metadata/RunTestsInSeparateProcesses.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RunTestsInSeparateProcesses extends Metadata +{ + public function isRunTestsInSeparateProcesses(): true + { + return true; + } +} diff --git a/src/Metadata/Test.php b/src/Metadata/Test.php new file mode 100644 index 00000000000..04007610a76 --- /dev/null +++ b/src/Metadata/Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Test extends Metadata +{ + public function isTest(): true + { + return true; + } +} diff --git a/src/Metadata/TestDox.php b/src/Metadata/TestDox.php new file mode 100644 index 00000000000..6e2944e5fe9 --- /dev/null +++ b/src/Metadata/TestDox.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDox extends Metadata +{ + /** + * @var non-empty-string + */ + private string $text; + + /** + * @param int<0, 1> $level + * @param non-empty-string $text + */ + protected function __construct(int $level, string $text) + { + parent::__construct($level); + + $this->text = $text; + } + + public function isTestDox(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function text(): string + { + return $this->text; + } +} diff --git a/src/Metadata/TestDoxFormatter.php b/src/Metadata/TestDoxFormatter.php new file mode 100644 index 00000000000..a7f055b87ef --- /dev/null +++ b/src/Metadata/TestDoxFormatter.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestDoxFormatter extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + } + + public function isTestDoxFormatter(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Metadata/TestWith.php b/src/Metadata/TestWith.php new file mode 100644 index 00000000000..d704d863fc4 --- /dev/null +++ b/src/Metadata/TestWith.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestWith extends Metadata +{ + private mixed $data; + + /** + * @var ?non-empty-string + */ + private ?string $name; + + /** + * @param int<0, 1> $level + * @param ?non-empty-string $name + */ + protected function __construct(int $level, mixed $data, ?string $name = null) + { + parent::__construct($level); + + $this->data = $data; + $this->name = $name; + } + + public function isTestWith(): true + { + return true; + } + + public function data(): mixed + { + return $this->data; + } + + /** + * @phpstan-assert-if-true !null $this->name + */ + public function hasName(): bool + { + return $this->name !== null; + } + + /** + * @return ?non-empty-string + */ + public function name(): ?string + { + return $this->name; + } +} diff --git a/src/Metadata/UsesClass.php b/src/Metadata/UsesClass.php new file mode 100644 index 00000000000..edbd03ac59b --- /dev/null +++ b/src/Metadata/UsesClass.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClass extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param int<0, 1> $level + * @param class-string $className + */ + protected function __construct(int $level, string $className) + { + parent::__construct($level); + + $this->className = $className; + } + + public function isUsesClass(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Metadata/UsesClassesThatExtendClass.php b/src/Metadata/UsesClassesThatExtendClass.php new file mode 100644 index 00000000000..baddfeb6b6f --- /dev/null +++ b/src/Metadata/UsesClassesThatExtendClass.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClassesThatExtendClass extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @param int<0, 1> $level + * @param class-string $className + */ + protected function __construct(int $level, string $className) + { + parent::__construct($level); + + $this->className = $className; + } + + public function isUsesClassesThatExtendClass(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } +} diff --git a/src/Metadata/UsesClassesThatImplementInterface.php b/src/Metadata/UsesClassesThatImplementInterface.php new file mode 100644 index 00000000000..5cdc6f629a3 --- /dev/null +++ b/src/Metadata/UsesClassesThatImplementInterface.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesClassesThatImplementInterface extends Metadata +{ + /** + * @var class-string + */ + private string $interfaceName; + + /** + * @param int<0, 1> $level + * @param class-string $interfaceName + */ + protected function __construct(int $level, string $interfaceName) + { + parent::__construct($level); + + $this->interfaceName = $interfaceName; + } + + public function isUsesClassesThatImplementInterface(): true + { + return true; + } + + /** + * @return class-string + */ + public function interfaceName(): string + { + return $this->interfaceName; + } +} diff --git a/src/Metadata/UsesFunction.php b/src/Metadata/UsesFunction.php new file mode 100644 index 00000000000..ec6cafee8e4 --- /dev/null +++ b/src/Metadata/UsesFunction.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesFunction extends Metadata +{ + /** + * @var non-empty-string + */ + private string $functionName; + + /** + * @param int<0, 1> $level + * @param non-empty-string $functionName + */ + public function __construct(int $level, string $functionName) + { + parent::__construct($level); + + $this->functionName = $functionName; + } + + public function isUsesFunction(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function functionName(): string + { + return $this->functionName; + } +} diff --git a/src/Metadata/UsesMethod.php b/src/Metadata/UsesMethod.php new file mode 100644 index 00000000000..6fc78f8f2c7 --- /dev/null +++ b/src/Metadata/UsesMethod.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesMethod extends Metadata +{ + /** + * @var class-string + */ + private string $className; + + /** + * @var non-empty-string + */ + private string $methodName; + + /** + * @param int<0, 1> $level + * @param class-string $className + * @param non-empty-string $methodName + */ + protected function __construct(int $level, string $className, string $methodName) + { + parent::__construct($level); + + $this->className = $className; + $this->methodName = $methodName; + } + + public function isUsesMethod(): true + { + return true; + } + + /** + * @return class-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } +} diff --git a/src/Metadata/UsesNamespace.php b/src/Metadata/UsesNamespace.php new file mode 100644 index 00000000000..f5e5d01ecd6 --- /dev/null +++ b/src/Metadata/UsesNamespace.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesNamespace extends Metadata +{ + /** + * @var non-empty-string + */ + private string $namespace; + + /** + * @param int<0, 1> $level + * @param non-empty-string $namespace + */ + protected function __construct(int $level, string $namespace) + { + parent::__construct($level); + + $this->namespace = $namespace; + } + + public function isUsesNamespace(): true + { + return true; + } + + /** + * @return class-string + */ + public function namespace(): string + { + return $this->namespace; + } +} diff --git a/src/Metadata/UsesTrait.php b/src/Metadata/UsesTrait.php new file mode 100644 index 00000000000..19490f26c2f --- /dev/null +++ b/src/Metadata/UsesTrait.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UsesTrait extends Metadata +{ + /** + * @var trait-string + */ + private string $traitName; + + /** + * @param 0|1 $level + * @param trait-string $traitName + */ + protected function __construct(int $level, string $traitName) + { + parent::__construct($level); + + $this->traitName = $traitName; + } + + public function isUsesTrait(): true + { + return true; + } + + /** + * @return trait-string + */ + public function traitName(): string + { + return $this->traitName; + } +} diff --git a/src/Metadata/Version/ComparisonRequirement.php b/src/Metadata/Version/ComparisonRequirement.php new file mode 100644 index 00000000000..b3b6a1fcadf --- /dev/null +++ b/src/Metadata/Version/ComparisonRequirement.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function version_compare; +use PHPUnit\Util\VersionComparisonOperator; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ComparisonRequirement extends Requirement +{ + private string $version; + private VersionComparisonOperator $operator; + + public function __construct(string $version, VersionComparisonOperator $operator) + { + $this->version = $version; + $this->operator = $operator; + } + + public function isSatisfiedBy(string $version): bool + { + return version_compare($version, $this->version, $this->operator->asString()); + } + + public function asString(): string + { + return $this->operator->asString() . ' ' . $this->version; + } +} diff --git a/src/Metadata/Version/ConstraintRequirement.php b/src/Metadata/Version/ConstraintRequirement.php new file mode 100644 index 00000000000..107544503b7 --- /dev/null +++ b/src/Metadata/Version/ConstraintRequirement.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function preg_replace; +use PharIo\Version\Version; +use PharIo\Version\VersionConstraint; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConstraintRequirement extends Requirement +{ + private VersionConstraint $constraint; + + public function __construct(VersionConstraint $constraint) + { + $this->constraint = $constraint; + } + + public function isSatisfiedBy(string $version): bool + { + return $this->constraint->complies( + new Version($this->sanitize($version)), + ); + } + + public function asString(): string + { + return $this->constraint->asString(); + } + + private function sanitize(string $version): string + { + return preg_replace( + '/^(\d+\.\d+(?:.\d+)?).*$/', + '$1', + $version, + ); + } +} diff --git a/src/Metadata/Version/Requirement.php b/src/Metadata/Version/Requirement.php new file mode 100644 index 00000000000..01f98f7310f --- /dev/null +++ b/src/Metadata/Version/Requirement.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Version; + +use function preg_match; +use PharIo\Version\UnsupportedVersionConstraintException; +use PharIo\Version\VersionConstraintParser; +use PHPUnit\Metadata\InvalidVersionRequirementException; +use PHPUnit\Util\InvalidVersionOperatorException; +use PHPUnit\Util\VersionComparisonOperator; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Requirement +{ + private const string VERSION_COMPARISON = "/(?P!=|<|<=|<>|=|==|>|>=)?\s*(?P[\d\.-]+(dev|(RC|alpha|beta)[\d\.])?)[ \t]*\r?$/m"; + + /** + * @throws InvalidVersionOperatorException + * @throws InvalidVersionRequirementException + */ + public static function from(string $versionRequirement): self + { + try { + return new ConstraintRequirement( + (new VersionConstraintParser)->parse( + $versionRequirement, + ), + ); + } catch (UnsupportedVersionConstraintException) { + if (preg_match(self::VERSION_COMPARISON, $versionRequirement, $matches) > 0) { + return new ComparisonRequirement( + $matches['version'], + new VersionComparisonOperator( + $matches['operator'] !== '' ? $matches['operator'] : '>=', + ), + ); + } + } + + throw new InvalidVersionRequirementException; + } + + abstract public function isSatisfiedBy(string $version): bool; + + abstract public function asString(): string; +} diff --git a/src/Metadata/WithEnvironmentVariable.php b/src/Metadata/WithEnvironmentVariable.php new file mode 100644 index 00000000000..cc4d0fe7dd0 --- /dev/null +++ b/src/Metadata/WithEnvironmentVariable.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WithEnvironmentVariable extends Metadata +{ + /** + * @var non-empty-string + */ + private string $environmentVariableName; + private null|string $value; + + /** + * @param non-empty-string $environmentVariableName + */ + public function __construct(int $level, string $environmentVariableName, null|string $value) + { + parent::__construct($level); + + $this->environmentVariableName = $environmentVariableName; + $this->value = $value; + } + + public function isWithEnvironmentVariable(): true + { + return true; + } + + /** + * @return non-empty-string + */ + public function environmentVariableName(): string + { + return $this->environmentVariableName; + } + + public function value(): null|string + { + return $this->value; + } +} diff --git a/src/Metadata/WithoutErrorHandler.php b/src/Metadata/WithoutErrorHandler.php new file mode 100644 index 00000000000..a8bf001475d --- /dev/null +++ b/src/Metadata/WithoutErrorHandler.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class WithoutErrorHandler extends Metadata +{ + public function isWithoutErrorHandler(): true + { + return true; + } +} diff --git a/src/Runner/BackedUpEnvironmentVariable.php b/src/Runner/BackedUpEnvironmentVariable.php new file mode 100644 index 00000000000..a62ebe95c17 --- /dev/null +++ b/src/Runner/BackedUpEnvironmentVariable.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function getenv; +use function putenv; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BackedUpEnvironmentVariable +{ + private const string FROM_GETENV = 'getenv'; + private const string FROM_SUPERGLOBAL = 'superglobal'; + + /** + * @var self::FROM_GETENV|self::FROM_SUPERGLOBAL + */ + private string $from; + + /** + * @var non-empty-string + */ + private string $name; + private null|string $value; + + /** + * @param non-empty-string $name + * + * @return array{0: self, 1: self} + */ + public static function create(string $name): array + { + $getenv = getenv($name); + + if ($getenv === false) { + $getenv = null; + } + + return [ + new self(self::FROM_SUPERGLOBAL, $name, $_ENV[$name] ?? null), + new self(self::FROM_GETENV, $name, $getenv), + ]; + } + + /** + * @param self::FROM_GETENV|self::FROM_SUPERGLOBAL $from + * @param non-empty-string $name + */ + private function __construct(string $from, string $name, null|string $value) + { + $this->from = $from; + $this->name = $name; + $this->value = $value; + } + + public function restore(): void + { + if ($this->from === self::FROM_GETENV) { + $this->restoreGetEnv(); + } else { + $this->restoreSuperGlobal(); + } + } + + private function restoreGetEnv(): void + { + if ($this->value === null) { + putenv($this->name); + } else { + putenv("{$this->name}={$this->value}"); + } + } + + private function restoreSuperGlobal(): void + { + if ($this->value === null) { + unset($_ENV[$this->name]); + } else { + $_ENV[$this->name] = $this->value; + } + } +} diff --git a/src/Runner/Baseline/Baseline.php b/src/Runner/Baseline/Baseline.php new file mode 100644 index 00000000000..cffc3791d58 --- /dev/null +++ b/src/Runner/Baseline/Baseline.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Baseline +{ + public const int VERSION = 1; + + /** + * @var array>> + */ + private array $issues = []; + + public function add(Issue $issue): void + { + if (!isset($this->issues[$issue->file()])) { + $this->issues[$issue->file()] = []; + } + + if (!isset($this->issues[$issue->file()][$issue->line()])) { + $this->issues[$issue->file()][$issue->line()] = []; + } + + $this->issues[$issue->file()][$issue->line()][] = $issue; + } + + public function has(Issue $issue): bool + { + if (!isset($this->issues[$issue->file()][$issue->line()])) { + return false; + } + + foreach ($this->issues[$issue->file()][$issue->line()] as $_issue) { + if ($_issue->equals($issue)) { + return true; + } + } + + return false; + } + + /** + * @return array>> + */ + public function groupedByFileAndLine(): array + { + return $this->issues; + } +} diff --git a/src/Runner/Baseline/Exception/CannotLoadBaselineException.php b/src/Runner/Baseline/Exception/CannotLoadBaselineException.php new file mode 100644 index 00000000000..c55901365e6 --- /dev/null +++ b/src/Runner/Baseline/Exception/CannotLoadBaselineException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Runner\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotLoadBaselineException extends RuntimeException implements Exception +{ +} diff --git a/src/Runner/Baseline/Exception/CannotWriteBaselineException.php b/src/Runner/Baseline/Exception/CannotWriteBaselineException.php new file mode 100644 index 00000000000..914a2c34db7 --- /dev/null +++ b/src/Runner/Baseline/Exception/CannotWriteBaselineException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Runner\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotWriteBaselineException extends RuntimeException implements Exception +{ +} diff --git a/src/Runner/Baseline/Exception/FileDoesNotHaveLineException.php b/src/Runner/Baseline/Exception/FileDoesNotHaveLineException.php new file mode 100644 index 00000000000..20c6ca03056 --- /dev/null +++ b/src/Runner/Baseline/Exception/FileDoesNotHaveLineException.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function sprintf; +use PHPUnit\Runner\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FileDoesNotHaveLineException extends RuntimeException implements Exception +{ + public function __construct(string $file, int $line) + { + parent::__construct( + sprintf( + 'File "%s" does not have line %d', + $file, + $line, + ), + ); + } +} diff --git a/src/Runner/Baseline/Generator.php b/src/Runner/Baseline/Generator.php new file mode 100644 index 00000000000..c5ce074de98 --- /dev/null +++ b/src/Runner/Baseline/Generator.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Runner\FileDoesNotExistException; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Generator +{ + private Baseline $baseline; + private Source $source; + + public function __construct(Facade $facade, Source $source) + { + $facade->registerSubscribers( + new TestTriggeredDeprecationSubscriber($this), + new TestTriggeredNoticeSubscriber($this), + new TestTriggeredPhpDeprecationSubscriber($this), + new TestTriggeredPhpNoticeSubscriber($this), + new TestTriggeredPhpWarningSubscriber($this), + new TestTriggeredWarningSubscriber($this), + ); + + $this->baseline = new Baseline; + $this->source = $source; + } + + public function baseline(): Baseline + { + return $this->baseline; + } + + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function testTriggeredIssue(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): void + { + if ($event->wasSuppressed() && !$this->isSuppressionIgnored($event)) { + return; + } + + if ($this->restrict($event) && !SourceFilter::instance()->includes($event->file())) { + return; + } + + $this->baseline->add( + Issue::from( + $event->file(), + $event->line(), + null, + $event->message(), + ), + ); + } + + private function restrict(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): bool + { + if ($event instanceof WarningTriggered || $event instanceof PhpWarningTriggered) { + return $this->source->restrictWarnings(); + } + + if ($event instanceof NoticeTriggered || $event instanceof PhpNoticeTriggered) { + return $this->source->restrictNotices(); + } + + return false; + } + + private function isSuppressionIgnored(DeprecationTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): bool + { + if ($event instanceof WarningTriggered) { + return $this->source->ignoreSuppressionOfWarnings(); + } + + if ($event instanceof PhpWarningTriggered) { + return $this->source->ignoreSuppressionOfPhpWarnings(); + } + + if ($event instanceof PhpNoticeTriggered) { + return $this->source->ignoreSuppressionOfPhpNotices(); + } + + if ($event instanceof NoticeTriggered) { + return $this->source->ignoreSuppressionOfNotices(); + } + + if ($event instanceof PhpDeprecationTriggered) { + return $this->source->ignoreSuppressionOfPhpDeprecations(); + } + + return $this->source->ignoreSuppressionOfDeprecations(); + } +} diff --git a/src/Runner/Baseline/Issue.php b/src/Runner/Baseline/Issue.php new file mode 100644 index 00000000000..869ea26a4bc --- /dev/null +++ b/src/Runner/Baseline/Issue.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use const FILE_IGNORE_NEW_LINES; +use function assert; +use function file; +use function is_file; +use function sha1; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Issue +{ + /** + * @var non-empty-string + */ + private string $file; + + /** + * @var positive-int + */ + private int $line; + + /** + * @var non-empty-string + */ + private string $hash; + + /** + * @var non-empty-string + */ + private string $description; + + /** + * @param non-empty-string $file + * @param positive-int $line + * @param ?non-empty-string $hash + * @param non-empty-string $description + * + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public static function from(string $file, int $line, ?string $hash, string $description): self + { + if ($hash === null) { + $hash = self::calculateHash($file, $line); + } + + return new self($file, $line, $hash, $description); + } + + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $hash + * @param non-empty-string $description + */ + private function __construct(string $file, int $line, string $hash, string $description) + { + $this->file = $file; + $this->line = $line; + $this->hash = $hash; + $this->description = $description; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + /** + * @return non-empty-string + */ + public function hash(): string + { + return $this->hash; + } + + /** + * @return non-empty-string + */ + public function description(): string + { + return $this->description; + } + + public function equals(self $other): bool + { + return $this->file() === $other->file() && + $this->line() === $other->line() && + $this->hash() === $other->hash() && + $this->description() === $other->description(); + } + + /** + * @param non-empty-string $file + * @param positive-int $line + * + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + * + * @return non-empty-string + */ + private static function calculateHash(string $file, int $line): string + { + $lines = @file($file, FILE_IGNORE_NEW_LINES); + + if ($lines === false && !is_file($file)) { + throw new FileDoesNotExistException($file); + } + + $key = $line - 1; + + if (!isset($lines[$key])) { + throw new FileDoesNotHaveLineException($file, $line); + } + + $hash = sha1($lines[$key]); + + assert($hash !== ''); + + return $hash; + } +} diff --git a/src/Runner/Baseline/Reader.php b/src/Runner/Baseline/Reader.php new file mode 100644 index 00000000000..ce3a194ff16 --- /dev/null +++ b/src/Runner/Baseline/Reader.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function dirname; +use function is_file; +use function realpath; +use function sprintf; +use function str_replace; +use function trim; +use DOMElement; +use DOMXPath; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Reader +{ + /** + * @param non-empty-string $baselineFile + * + * @throws CannotLoadBaselineException + */ + public function read(string $baselineFile): Baseline + { + if (!is_file($baselineFile)) { + throw new CannotLoadBaselineException( + sprintf( + 'Cannot read baseline %s, file does not exist', + $baselineFile, + ), + ); + } + + try { + $document = (new XmlLoader)->loadFile($baselineFile); + } catch (XmlException $e) { + throw new CannotLoadBaselineException( + sprintf( + 'Cannot read baseline %s: %s', + $baselineFile, + trim($e->getMessage()), + ), + ); + } + + $version = (int) $document->documentElement->getAttribute('version'); + + if ($version !== Baseline::VERSION) { + throw new CannotLoadBaselineException( + sprintf( + 'Cannot read baseline %s, version %d is not supported', + $baselineFile, + $version, + ), + ); + } + + $baseline = new Baseline; + $baselineDirectory = dirname(realpath($baselineFile)); + $xpath = new DOMXPath($document); + + foreach ($xpath->query('file') as $fileElement) { + assert($fileElement instanceof DOMElement); + + $file = $baselineDirectory . DIRECTORY_SEPARATOR . str_replace('/', DIRECTORY_SEPARATOR, $fileElement->getAttribute('path')); + + foreach ($xpath->query('line', $fileElement) as $lineElement) { + assert($lineElement instanceof DOMElement); + + $line = (int) $lineElement->getAttribute('number'); + $hash = $lineElement->getAttribute('hash'); + + foreach ($xpath->query('issue', $lineElement) as $issueElement) { + assert($issueElement instanceof DOMElement); + + $description = $issueElement->textContent; + + assert($line > 0); + assert($hash !== ''); + assert($description !== ''); + + $baseline->add(Issue::from($file, $line, $hash, $description)); + } + } + } + + return $baseline; + } +} diff --git a/src/Runner/Baseline/RelativePathCalculator.php b/src/Runner/Baseline/RelativePathCalculator.php new file mode 100644 index 00000000000..a05e6bbea09 --- /dev/null +++ b/src/Runner/Baseline/RelativePathCalculator.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function array_fill; +use function array_merge; +use function array_slice; +use function assert; +use function count; +use function explode; +use function implode; +use function str_replace; +use function strpos; +use function substr; +use function trim; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see Copied from https://github.com/phpstan/phpstan-src/blob/1.10.33/src/File/ParentDirectoryRelativePathHelper.php + */ +final readonly class RelativePathCalculator +{ + /** + * @var non-empty-string + */ + private string $baselineDirectory; + + /** + * @param non-empty-string $baselineDirectory + */ + public function __construct(string $baselineDirectory) + { + $this->baselineDirectory = $baselineDirectory; + } + + /** + * @param non-empty-string $filename + * + * @return non-empty-string + */ + public function calculate(string $filename): string + { + $result = implode('/', $this->parts($filename)); + + assert($result !== ''); + + return $result; + } + + /** + * @param non-empty-string $filename + * + * @return list + */ + public function parts(string $filename): array + { + $schemePosition = strpos($filename, '://'); + + if ($schemePosition !== false) { + $filename = substr($filename, $schemePosition + 3); + + assert($filename !== ''); + } + + $parentParts = explode('/', trim(str_replace('\\', '/', $this->baselineDirectory), '/')); + $parentPartsCount = count($parentParts); + $filenameParts = explode('/', trim(str_replace('\\', '/', $filename), '/')); + $filenamePartsCount = count($filenameParts); + + $i = 0; + + for (; $i < $filenamePartsCount; $i++) { + if ($parentPartsCount < $i + 1) { + break; + } + + $parentPath = implode('/', array_slice($parentParts, 0, $i + 1)); + $filenamePath = implode('/', array_slice($filenameParts, 0, $i + 1)); + + if ($parentPath !== $filenamePath) { + break; + } + } + + if ($i === 0) { + return [$filename]; + } + + $dotsCount = $parentPartsCount - $i; + + assert($dotsCount >= 0); + + return array_merge(array_fill(0, $dotsCount, '..'), array_slice($filenameParts, $i)); + } +} diff --git a/src/Runner/Baseline/Subscriber/Subscriber.php b/src/Runner/Baseline/Subscriber/Subscriber.php new file mode 100644 index 00000000000..59ca634b1be --- /dev/null +++ b/src/Runner/Baseline/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private Generator $generator; + + public function __construct(Generator $generator) + { + $this->generator = $generator; + } + + protected function generator(): Generator + { + return $this->generator; + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..72e26110609 --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredDeprecationSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(DeprecationTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.php new file mode 100644 index 00000000000..288d0eff020 --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredNoticeSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(NoticeTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php new file mode 100644 index 00000000000..f72095ac18d --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredPhpDeprecationSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpDeprecationTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php new file mode 100644 index 00000000000..9707a46b3fb --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredPhpNoticeSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpNoticeTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php new file mode 100644 index 00000000000..22af95db419 --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredPhpWarningSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(PhpWarningTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.php b/src/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.php new file mode 100644 index 00000000000..fd5e0db6fc1 --- /dev/null +++ b/src/Runner/Baseline/Subscriber/TestTriggeredWarningSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; +use PHPUnit\Runner\FileDoesNotExistException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber +{ + /** + * @throws FileDoesNotExistException + * @throws FileDoesNotHaveLineException + */ + public function notify(WarningTriggered $event): void + { + $this->generator()->testTriggeredIssue($event); + } +} diff --git a/src/Runner/Baseline/Writer.php b/src/Runner/Baseline/Writer.php new file mode 100644 index 00000000000..7d7d7645b71 --- /dev/null +++ b/src/Runner/Baseline/Writer.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function dirname; +use function file_put_contents; +use function is_dir; +use function realpath; +use function sprintf; +use XMLWriter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Writer +{ + /** + * @param non-empty-string $baselineFile + * + * @throws CannotWriteBaselineException + */ + public function write(string $baselineFile, Baseline $baseline): void + { + $normalizedBaselineFile = realpath(dirname($baselineFile)); + + if ($normalizedBaselineFile === false || !is_dir($normalizedBaselineFile)) { + throw new CannotWriteBaselineException(sprintf('Cannot write baseline to "%s".', $baselineFile)); + } + + $pathCalculator = new RelativePathCalculator($normalizedBaselineFile); + + $writer = new XMLWriter; + + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument(); + + $writer->startElement('files'); + $writer->writeAttribute('version', (string) Baseline::VERSION); + + foreach ($baseline->groupedByFileAndLine() as $file => $lines) { + $writer->startElement('file'); + $writer->writeAttribute('path', $pathCalculator->calculate($file)); + + foreach ($lines as $line => $issues) { + $writer->startElement('line'); + $writer->writeAttribute('number', (string) $line); + $writer->writeAttribute('hash', $issues[0]->hash()); + + foreach ($issues as $issue) { + $writer->startElement('issue'); + $writer->writeCdata($issue->description()); + $writer->endElement(); + } + + $writer->endElement(); + } + + $writer->endElement(); + } + + $writer->endElement(); + + file_put_contents($baselineFile, $writer->outputMemory()); + } +} diff --git a/src/Runner/CodeCoverage.php b/src/Runner/CodeCoverage.php new file mode 100644 index 00000000000..7bc49d24d4b --- /dev/null +++ b/src/Runner/CodeCoverage.php @@ -0,0 +1,491 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function assert; +use function file_put_contents; +use function sprintf; +use function sys_get_temp_dir; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Filesystem; +use SebastianBergmann\CodeCoverage\Driver\Driver; +use SebastianBergmann\CodeCoverage\Driver\Selector; +use SebastianBergmann\CodeCoverage\Exception as CodeCoverageException; +use SebastianBergmann\CodeCoverage\Filter; +use SebastianBergmann\CodeCoverage\Report\Clover as CloverReport; +use SebastianBergmann\CodeCoverage\Report\Cobertura as CoberturaReport; +use SebastianBergmann\CodeCoverage\Report\Crap4j as Crap4jReport; +use SebastianBergmann\CodeCoverage\Report\Html\Colors; +use SebastianBergmann\CodeCoverage\Report\Html\CustomCssFile; +use SebastianBergmann\CodeCoverage\Report\Html\Facade as HtmlReport; +use SebastianBergmann\CodeCoverage\Report\OpenClover as OpenCloverReport; +use SebastianBergmann\CodeCoverage\Report\PHP as PhpReport; +use SebastianBergmann\CodeCoverage\Report\Text as TextReport; +use SebastianBergmann\CodeCoverage\Report\Thresholds; +use SebastianBergmann\CodeCoverage\Report\Xml\Facade as XmlReport; +use SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer; +use SebastianBergmann\CodeCoverage\Test\Target\TargetCollection; +use SebastianBergmann\CodeCoverage\Test\Target\ValidationFailure; +use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize; +use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; +use SebastianBergmann\Comparator\Comparator; +use SebastianBergmann\Timer\NoActiveTimerException; +use SebastianBergmann\Timer\Timer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class CodeCoverage +{ + private static ?self $instance = null; + private ?\SebastianBergmann\CodeCoverage\CodeCoverage $codeCoverage = null; + + /** + * @phpstan-ignore property.internalClass + */ + private ?Driver $driver = null; + private bool $collecting = false; + private ?TestCase $test = null; + private ?Timer $timer = null; + + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self; + } + + return self::$instance; + } + + public function init(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry, bool $extensionRequiresCodeCoverageCollection): CodeCoverageInitializationStatus + { + $codeCoverageFilterRegistry->init($configuration); + + if (!$configuration->hasCoverageReport() && !$extensionRequiresCodeCoverageCollection) { + return CodeCoverageInitializationStatus::NOT_REQUESTED; + } + + $this->activate($codeCoverageFilterRegistry->get(), $configuration->pathCoverage()); + + if (!$this->isActive()) { + return CodeCoverageInitializationStatus::FAILED; + } + + if ($configuration->hasCoverageCacheDirectory()) { + $coverageCacheDirectory = $configuration->coverageCacheDirectory(); + } else { + $candidate = sys_get_temp_dir() . '/phpunit-code-coverage-cache'; + + if (Filesystem::createDirectory($candidate)) { + $coverageCacheDirectory = $candidate; + } + } + + if (isset($coverageCacheDirectory)) { + $this->codeCoverage()->cacheStaticAnalysis($coverageCacheDirectory); + } + + $this->codeCoverage()->excludeSubclassesOfThisClassFromUnintentionallyCoveredCodeCheck(Comparator::class); + + if ($configuration->strictCoverage()) { + $this->codeCoverage()->enableCheckForUnintentionallyCoveredCode(); + } + + if ($configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage()) { + $this->codeCoverage()->ignoreDeprecatedCode(); + } else { + $this->codeCoverage()->doNotIgnoreDeprecatedCode(); + } + + if ($configuration->disableCodeCoverageIgnore()) { + $this->codeCoverage()->disableAnnotationsForIgnoringCode(); + } else { + $this->codeCoverage()->enableAnnotationsForIgnoringCode(); + } + + if ($configuration->includeUncoveredFiles()) { + $this->codeCoverage()->includeUncoveredFiles(); + } else { + $this->codeCoverage()->excludeUncoveredFiles(); + } + + if ($codeCoverageFilterRegistry->get()->isEmpty()) { + if (!$codeCoverageFilterRegistry->configured()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + 'No filter is configured, code coverage will not be processed', + ); + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + 'Incorrect filter configuration, code coverage will not be processed', + ); + } + + $this->deactivate(); + } + + if (isset($coverageCacheDirectory) && $configuration->includeUncoveredFiles()) { + EventFacade::emitter()->testRunnerStartedStaticAnalysisForCodeCoverage(); + + /** @phpstan-ignore new.internalClass,method.internalClass */ + $statistics = (new CacheWarmer)->warmCache( + $coverageCacheDirectory, + !$configuration->disableCodeCoverageIgnore(), + $configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), + $codeCoverageFilterRegistry->get(), + ); + + EventFacade::emitter()->testRunnerFinishedStaticAnalysisForCodeCoverage( + $statistics['cacheHits'], + $statistics['cacheMisses'], + ); + } + + return CodeCoverageInitializationStatus::SUCCEEDED; + } + + /** + * @phpstan-assert-if-true !null $this->codeCoverage + */ + public function isActive(): bool + { + return $this->codeCoverage !== null; + } + + public function codeCoverage(): \SebastianBergmann\CodeCoverage\CodeCoverage + { + return $this->codeCoverage; + } + + /** + * @return non-empty-string + */ + public function driverNameAndVersion(): string + { + return $this->driver->nameAndVersion(); + } + + public function start(TestCase $test): void + { + if ($this->collecting) { + return; + } + + $size = TestSize::unknown(); + + if ($test->size()->isSmall()) { + $size = TestSize::small(); + } elseif ($test->size()->isMedium()) { + $size = TestSize::medium(); + } elseif ($test->size()->isLarge()) { + $size = TestSize::large(); + } + + $this->test = $test; + + $this->codeCoverage->start( + $test->valueObjectForEvents()->id(), + $size, + ); + + $this->collecting = true; + + $this->timer()->start(); + } + + public function stop(bool $append, null|false|TargetCollection $covers = null, ?TargetCollection $uses = null): void + { + if (!$this->collecting) { + return; + } + + $time = $this->timer()->stop()->asSeconds(); + $status = TestStatus::unknown(); + $this->collecting = false; + + if ($this->test !== null) { + if ($this->test->status()->isSuccess()) { + $status = TestStatus::success(); + } else { + $status = TestStatus::failure(); + } + } + + if ($covers instanceof TargetCollection) { + $result = $this->codeCoverage->validate($covers); + + if ($result->isFailure()) { + assert($result instanceof ValidationFailure); + + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->test->valueObjectForEvents(), + $result->message(), + ); + + $append = false; + } + } + + if ($uses instanceof TargetCollection) { + $result = $this->codeCoverage->validate($uses); + + if ($result->isFailure()) { + assert($result instanceof ValidationFailure); + + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->test->valueObjectForEvents(), + $result->message(), + ); + + $append = false; + } + } + + $this->codeCoverage->stop($append, $status, $covers, $uses, $time); + + $this->test = null; + } + + public function deactivate(): void + { + $this->driver = null; + $this->codeCoverage = null; + $this->test = null; + } + + public function generateReports(Printer $printer, Configuration $configuration): void + { + if (!$this->isActive()) { + return; + } + + if ($configuration->hasCoveragePhp()) { + $this->codeCoverageGenerationStart($printer, 'PHP'); + + try { + $writer = new PhpReport; + $writer->process($this->codeCoverage(), $configuration->coveragePhp()); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageClover()) { + $this->codeCoverageGenerationStart($printer, 'Clover XML'); + + try { + $writer = new CloverReport; + $writer->process($this->codeCoverage(), $configuration->coverageClover(), 'Clover Coverage'); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageOpenClover()) { + $this->codeCoverageGenerationStart($printer, 'OpenClover XML'); + + try { + $writer = new OpenCloverReport; + $writer->process($this->codeCoverage(), $configuration->coverageOpenClover(), 'OpenClover Coverage'); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageCobertura()) { + $this->codeCoverageGenerationStart($printer, 'Cobertura XML'); + + try { + $writer = new CoberturaReport; + $writer->process($this->codeCoverage(), $configuration->coverageCobertura()); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageCrap4j()) { + $this->codeCoverageGenerationStart($printer, 'Crap4J XML'); + + try { + $writer = new Crap4jReport($configuration->coverageCrap4jThreshold()); + $writer->process($this->codeCoverage(), $configuration->coverageCrap4j()); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageHtml()) { + $this->codeCoverageGenerationStart($printer, 'HTML'); + + try { + $customCssFile = CustomCssFile::default(); + + if ($configuration->hasCoverageHtmlCustomCssFile()) { + $customCssFile = CustomCssFile::from($configuration->coverageHtmlCustomCssFile()); + } + + $writer = new HtmlReport( + sprintf( + ' and PHPUnit %s', + Version::id(), + ), + Colors::from( + $configuration->coverageHtmlColorSuccessLow(), + $configuration->coverageHtmlColorSuccessMedium(), + $configuration->coverageHtmlColorSuccessHigh(), + $configuration->coverageHtmlColorWarning(), + $configuration->coverageHtmlColorDanger(), + ), + Thresholds::from( + $configuration->coverageHtmlLowUpperBound(), + $configuration->coverageHtmlHighLowerBound(), + ), + $customCssFile, + ); + + $writer->process($this->codeCoverage(), $configuration->coverageHtml()); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + + if ($configuration->hasCoverageText()) { + $processor = new TextReport( + Thresholds::default(), + $configuration->coverageTextShowUncoveredFiles(), + $configuration->coverageTextShowOnlySummary(), + ); + + $textReport = $processor->process($this->codeCoverage(), $configuration->colors()); + + if ($configuration->coverageText() === 'php://stdout') { + if (!$configuration->noOutput() && !$configuration->debug()) { + $printer->print($textReport); + } + } else { + file_put_contents($configuration->coverageText(), $textReport); + } + } + + if ($configuration->hasCoverageXml()) { + $this->codeCoverageGenerationStart($printer, 'PHPUnit XML'); + + try { + $writer = new XmlReport(Version::id(), $configuration->coverageXmlIncludeSource()); + $writer->process($this->codeCoverage(), $configuration->coverageXml()); + + $this->codeCoverageGenerationSucceeded($printer); + + unset($writer); + } catch (CodeCoverageException $e) { + $this->codeCoverageGenerationFailed($printer, $e); + } + } + } + + private function activate(Filter $filter, bool $pathCoverage): void + { + try { + if ($pathCoverage) { + $this->driver = (new Selector)->forLineAndPathCoverage($filter); + } else { + $this->driver = (new Selector)->forLineCoverage($filter); + } + + $this->codeCoverage = new \SebastianBergmann\CodeCoverage\CodeCoverage( + $this->driver, + $filter, + ); + } catch (CodeCoverageException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + $e->getMessage(), + ); + } + } + + private function codeCoverageGenerationStart(Printer $printer, string $format): void + { + $printer->print( + sprintf( + "\nGenerating code coverage report in %s format ... ", + $format, + ), + ); + + $this->timer()->start(); + } + + /** + * @throws NoActiveTimerException + */ + private function codeCoverageGenerationSucceeded(Printer $printer): void + { + $printer->print( + sprintf( + "done [%s]\n", + $this->timer()->stop()->asString(), + ), + ); + } + + /** + * @throws NoActiveTimerException + */ + private function codeCoverageGenerationFailed(Printer $printer, CodeCoverageException $e): void + { + $printer->print( + sprintf( + "failed [%s]\n%s\n", + $this->timer()->stop()->asString(), + $e->getMessage(), + ), + ); + } + + private function timer(): Timer + { + if ($this->timer === null) { + $this->timer = new Timer; + } + + return $this->timer; + } +} diff --git a/src/Runner/CodeCoverageInitializationStatus.php b/src/Runner/CodeCoverageInitializationStatus.php new file mode 100644 index 00000000000..ce895f6e6cf --- /dev/null +++ b/src/Runner/CodeCoverageInitializationStatus.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This enumeration is not covered by the backward compatibility promise for PHPUnit + */ +enum CodeCoverageInitializationStatus +{ + case NOT_REQUESTED; + case SUCCEEDED; + case FAILED; +} diff --git a/src/Runner/DeprecationCollector/Collector.php b/src/Runner/DeprecationCollector/Collector.php new file mode 100644 index 00000000000..575bc2dd335 --- /dev/null +++ b/src/Runner/DeprecationCollector/Collector.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\TestRunner\IssueFilter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Collector +{ + private readonly IssueFilter $issueFilter; + + /** + * @var list + */ + private array $deprecations = []; + + /** + * @var list + */ + private array $filteredDeprecations = []; + + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $facade->registerSubscribers( + new TestPreparedSubscriber($this), + new TestTriggeredDeprecationSubscriber($this), + ); + + $this->issueFilter = $issueFilter; + } + + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + + /** + * @return list + */ + public function filteredDeprecations(): array + { + return $this->filteredDeprecations; + } + + public function testPrepared(): void + { + $this->deprecations = []; + } + + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + $this->deprecations[] = $event->message(); + + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + $this->filteredDeprecations[] = $event->message(); + } +} diff --git a/src/Runner/DeprecationCollector/Facade.php b/src/Runner/DeprecationCollector/Facade.php new file mode 100644 index 00000000000..a08fdc64c3b --- /dev/null +++ b/src/Runner/DeprecationCollector/Facade.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\UnknownSubscriberTypeException; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static null|Collector|InIsolationCollector $collector = null; + private static bool $inIsolation = false; + + public static function init(): void + { + self::collector(); + } + + public static function initForIsolation(): void + { + self::collector(); + + self::$inIsolation = true; + } + + /** + * @return list + */ + public static function deprecations(): array + { + return self::collector()->deprecations(); + } + + /** + * @return list + */ + public static function filteredDeprecations(): array + { + return self::collector()->filteredDeprecations(); + } + + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public static function collector(): Collector|InIsolationCollector + { + if (self::$collector !== null) { + return self::$collector; + } + + $issueFilter = new IssueFilter( + ConfigurationRegistry::get()->source(), + ); + + if (self::$inIsolation) { + self::$collector = new InIsolationCollector( + $issueFilter, + ); + + return self::$collector; + } + + self::$collector = new Collector( + EventFacade::instance(), + $issueFilter, + ); + + return self::$collector; + } +} diff --git a/src/Runner/DeprecationCollector/InIsolationCollector.php b/src/Runner/DeprecationCollector/InIsolationCollector.php new file mode 100644 index 00000000000..31287622175 --- /dev/null +++ b/src/Runner/DeprecationCollector/InIsolationCollector.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\TestRunner\IssueFilter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InIsolationCollector +{ + private readonly IssueFilter $issueFilter; + + /** + * @var list + */ + private array $deprecations = []; + + /** + * @var list + */ + private array $filteredDeprecations = []; + + public function __construct(IssueFilter $issueFilter) + { + $this->issueFilter = $issueFilter; + } + + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + + /** + * @return list + */ + public function filteredDeprecations(): array + { + return $this->filteredDeprecations; + } + + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + $this->deprecations[] = $event->message(); + + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + $this->filteredDeprecations[] = $event->message(); + } +} diff --git a/src/Runner/DeprecationCollector/Subscriber/Subscriber.php b/src/Runner/DeprecationCollector/Subscriber/Subscriber.php new file mode 100644 index 00000000000..65af6ab7060 --- /dev/null +++ b/src/Runner/DeprecationCollector/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class Subscriber +{ + private readonly Collector|InIsolationCollector $collector; + + public function __construct(Collector|InIsolationCollector $collector) + { + $this->collector = $collector; + } + + protected function collector(): Collector|InIsolationCollector + { + return $this->collector; + } +} diff --git a/src/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php b/src/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..0e78c31a422 --- /dev/null +++ b/src/Runner/DeprecationCollector/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared(); + } +} diff --git a/src/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php b/src/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..a01f1b61ea2 --- /dev/null +++ b/src/Runner/DeprecationCollector/Subscriber/TestTriggeredDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\DeprecationCollector; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} diff --git a/src/Runner/ErrorHandler.php b/src/Runner/ErrorHandler.php new file mode 100644 index 00000000000..e97d47886ea --- /dev/null +++ b/src/Runner/ErrorHandler.php @@ -0,0 +1,512 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const E_COMPILE_ERROR; +use const E_COMPILE_WARNING; +use const E_CORE_ERROR; +use const E_CORE_WARNING; +use const E_DEPRECATED; +use const E_ERROR; +use const E_NOTICE; +use const E_PARSE; +use const E_RECOVERABLE_ERROR; +use const E_USER_DEPRECATED; +use const E_USER_ERROR; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use const E_WARNING; +use function array_keys; +use function array_values; +use function assert; +use function debug_backtrace; +use function defined; +use function error_reporting; +use function preg_match; +use function restore_error_handler; +use function set_error_handler; +use function sprintf; +use PHPUnit\Event; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\IgnoreDeprecations; +use PHPUnit\Runner\Baseline\Baseline; +use PHPUnit\Runner\Baseline\Issue; +use PHPUnit\TextUI\Configuration\Registry; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; +use PHPUnit\Util\ExcludeList; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorHandler +{ + private const int UNHANDLEABLE_LEVELS = E_ERROR | E_PARSE | E_CORE_ERROR | E_CORE_WARNING | E_COMPILE_ERROR | E_COMPILE_WARNING; + private const int INSUPPRESSIBLE_LEVELS = E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR | E_RECOVERABLE_ERROR; + private static ?self $instance = null; + private ?Baseline $baseline = null; + private bool $enabled = false; + private ?int $originalErrorReportingLevel = null; + private readonly Source $source; + + /** + * @var list + */ + private array $globalDeprecations = []; + + /** + * @var array> + */ + private array $testCaseContextDeprecations = []; + private ?string $testCaseContext = null; + + /** + * @var ?array{functions: list, methods: list} + */ + private ?array $deprecationTriggers = null; + + public static function instance(): self + { + return self::$instance ?? self::$instance = new self(Registry::get()->source()); + } + + private function __construct(Source $source) + { + $this->source = $source; + } + + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public function __invoke(int $errorNumber, string $errorString, string $errorFile, int $errorLine): false + { + $suppressed = (error_reporting() & ~self::INSUPPRESSIBLE_LEVELS) === 0; + + if ($suppressed && (new ExcludeList)->isExcluded($errorFile)) { + return false; + } + + /** + * E_STRICT is deprecated since PHP 8.4. + * + * @see https://github.com/sebastianbergmann/phpunit/issues/5956 + */ + if (defined('E_STRICT') && $errorNumber === 2048) { + $errorNumber = E_NOTICE; + } + + $test = Event\Code\TestMethodBuilder::fromCallStack(); + + if ($errorNumber === E_USER_DEPRECATED) { + $deprecationFrame = $this->guessDeprecationFrame(); + $errorFile = $deprecationFrame['file'] ?? $errorFile; + $errorLine = $deprecationFrame['line'] ?? $errorLine; + } + + $ignoredByBaseline = $this->ignoredByBaseline($errorFile, $errorLine, $errorString); + $ignoredByTest = $this->deprecationIgnoredByTest($test, $errorString); + + switch ($errorNumber) { + case E_NOTICE: + Event\Facade::emitter()->testTriggeredPhpNotice( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + + break; + + case E_USER_NOTICE: + Event\Facade::emitter()->testTriggeredNotice( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + + break; + + case E_WARNING: + Event\Facade::emitter()->testTriggeredPhpWarning( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + + break; + + case E_USER_WARNING: + Event\Facade::emitter()->testTriggeredWarning( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + ); + + break; + + case E_DEPRECATED: + Event\Facade::emitter()->testTriggeredPhpDeprecation( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $this->trigger($test, false), + ); + + break; + + case E_USER_DEPRECATED: + Event\Facade::emitter()->testTriggeredDeprecation( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $this->trigger($test, true), + $this->stackTrace(), + ); + + break; + + case E_USER_ERROR: + Event\Facade::emitter()->testTriggeredError( + $test, + $errorString, + $errorFile, + $errorLine, + $suppressed, + ); + + throw new ErrorException('E_USER_ERROR was triggered'); + + default: + return false; + } + + return false; + } + + public function deprecationHandler(int $errorNumber, string $errorString, string $errorFile, int $errorLine): true + { + if ($this->testCaseContext !== null) { + $this->testCaseContextDeprecations[$this->testCaseContext][] = [$errorNumber, $errorString, $errorFile, $errorLine]; + } else { + $this->globalDeprecations[] = [$errorNumber, $errorString, $errorFile, $errorLine]; + } + + return true; + } + + public function registerDeprecationHandler(): void + { + set_error_handler([self::$instance, 'deprecationHandler'], E_USER_DEPRECATED | E_DEPRECATED); + } + + public function restoreDeprecationHandler(): void + { + restore_error_handler(); + } + + public function enable(TestCase $test): void + { + if ($this->enabled) { + return; + } + + $oldErrorHandler = set_error_handler($this); + + if ($oldErrorHandler !== null) { + restore_error_handler(); + + return; + } + + $this->enabled = true; + $this->originalErrorReportingLevel = error_reporting(); + + $this->triggerGlobalDeprecations($test); + + error_reporting($this->originalErrorReportingLevel & self::UNHANDLEABLE_LEVELS); + } + + public function disable(): void + { + if (!$this->enabled) { + return; + } + + restore_error_handler(); + + error_reporting(error_reporting() | $this->originalErrorReportingLevel); + + $this->enabled = false; + $this->originalErrorReportingLevel = null; + } + + public function useBaseline(Baseline $baseline): void + { + $this->baseline = $baseline; + } + + /** + * @param array{functions: list, methods: list} $deprecationTriggers + */ + public function useDeprecationTriggers(array $deprecationTriggers): void + { + $this->deprecationTriggers = $deprecationTriggers; + } + + public function enterTestCaseContext(string $className, string $methodName): void + { + $this->testCaseContext = $this->testCaseContext($className, $methodName); + } + + public function leaveTestCaseContext(): void + { + $this->testCaseContext = null; + } + + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + private function ignoredByBaseline(string $file, int $line, string $description): bool + { + if ($this->baseline === null) { + return false; + } + + return $this->baseline->has(Issue::from($file, $line, null, $description)); + } + + private function trigger(TestMethod $test, bool $filterTrigger): IssueTrigger + { + if (!$this->source->notEmpty()) { + return IssueTrigger::unknown(); + } + + $trace = $this->filteredStackTrace($filterTrigger); + + $triggeredInFirstPartyCode = false; + $triggerCalledFromFirstPartyCode = false; + + if (isset($trace[0]['file'])) { + if ($trace[0]['file'] === $test->file()) { + return IssueTrigger::test(); + } + + if (SourceFilter::instance()->includes($trace[0]['file'])) { + $triggeredInFirstPartyCode = true; + } + } + + if (isset($trace[1]['file']) && + ($trace[1]['file'] === $test->file() || + SourceFilter::instance()->includes($trace[1]['file']))) { + $triggerCalledFromFirstPartyCode = true; + } + + if ($triggerCalledFromFirstPartyCode) { + if ($triggeredInFirstPartyCode) { + return IssueTrigger::self(); + } + + return IssueTrigger::direct(); + } + + return IssueTrigger::indirect(); + } + + /** + * @return list + */ + private function filteredStackTrace(bool $filterDeprecationTriggers): array + { + $trace = $this->errorStackTrace(); + + if ($this->deprecationTriggers === null || !$filterDeprecationTriggers) { + return array_values($trace); + } + + foreach (array_keys($trace) as $frame) { + foreach ($this->deprecationTriggers['functions'] as $function) { + if ($this->frameIsFunction($trace[$frame], $function)) { + unset($trace[$frame]); + + continue 2; + } + } + + foreach ($this->deprecationTriggers['methods'] as $method) { + if ($this->frameIsMethod($trace[$frame], $method)) { + unset($trace[$frame]); + + continue 2; + } + } + } + + return array_values($trace); + } + + /** + * @return ?array{file: non-empty-string, line: positive-int} + */ + private function guessDeprecationFrame(): ?array + { + if ($this->deprecationTriggers === null) { + return null; + } + + $trace = $this->errorStackTrace(); + + foreach ($trace as $frame) { + foreach ($this->deprecationTriggers['functions'] as $function) { + if ($this->frameIsFunction($frame, $function)) { + return $frame; + } + } + + foreach ($this->deprecationTriggers['methods'] as $method) { + if ($this->frameIsMethod($frame, $method)) { + return $frame; + } + } + } + + return null; + } + + /** + * @return list + */ + private function errorStackTrace(): array + { + $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS); + + $i = 0; + + do { + unset($trace[$i]); + } while (self::class === ($trace[++$i]['class'] ?? null)); + + return array_values($trace); + } + + /** + * @param array{class? : class-string, function?: non-empty-string} $frame + * @param non-empty-string $function + */ + private function frameIsFunction(array $frame, string $function): bool + { + return !isset($frame['class']) && isset($frame['function']) && $frame['function'] === $function; + } + + /** + * @param array{class? : class-string, function?: non-empty-string} $frame + * @param array{className: class-string, methodName: non-empty-string} $method + */ + private function frameIsMethod(array $frame, array $method): bool + { + return isset($frame['class']) && + $frame['class'] === $method['className'] && + isset($frame['function']) && + $frame['function'] === $method['methodName']; + } + + /** + * @return non-empty-string + */ + private function stackTrace(): string + { + $buffer = ''; + $excludeList = new ExcludeList(true); + + foreach ($this->errorStackTrace() as $frame) { + /** + * @see https://github.com/sebastianbergmann/phpunit/issues/6043 + */ + if (!isset($frame['file'])) { + continue; + } + + if ($excludeList->isExcluded($frame['file'])) { + continue; + } + + $buffer .= sprintf( + "%s:%s\n", + $frame['file'], + $frame['line'] ?? '?', + ); + } + + return $buffer; + } + + private function triggerGlobalDeprecations(TestCase $test): void + { + foreach ($this->globalDeprecations ?? [] as $d) { + $this->__invoke(...$d); + } + + $testCaseContext = $this->testCaseContext($test::class, $test->name()); + + foreach ($this->testCaseContextDeprecations[$testCaseContext] ?? [] as $d) { + $this->__invoke(...$d); + } + } + + private function testCaseContext(string $className, string $methodName): string + { + return "{$className}::{$methodName}"; + } + + private function deprecationIgnoredByTest(TestMethod $test, string $message): bool + { + $metadata = \PHPUnit\Metadata\Parser\Registry::parser()->forClassAndMethod($test->className(), $test->methodName())->isIgnoreDeprecations()->asArray(); + + foreach ($metadata as $metadatum) { + assert($metadatum instanceof IgnoreDeprecations); + + $ignoreDeprecationMessagePattern = $metadatum->messagePattern(); + + if ($ignoreDeprecationMessagePattern === null || + (bool) preg_match('{' . $ignoreDeprecationMessagePattern . '}', $message)) { + return true; + } + } + + return false; + } +} diff --git a/src/Runner/Exception/ClassCannotBeFoundException.php b/src/Runner/Exception/ClassCannotBeFoundException.php new file mode 100644 index 00000000000..701cbb5b143 --- /dev/null +++ b/src/Runner/Exception/ClassCannotBeFoundException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassCannotBeFoundException extends RuntimeException implements Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct( + sprintf( + 'Class %s cannot be found in %s', + $className, + $file, + ), + ); + } +} diff --git a/src/Runner/Exception/ClassDoesNotExtendTestCaseException.php b/src/Runner/Exception/ClassDoesNotExtendTestCaseException.php new file mode 100644 index 00000000000..c9d5474e32c --- /dev/null +++ b/src/Runner/Exception/ClassDoesNotExtendTestCaseException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassDoesNotExtendTestCaseException extends RuntimeException implements Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct( + sprintf( + 'Class %s declared in %s does not extend PHPUnit\Framework\TestCase', + $className, + $file, + ), + ); + } +} diff --git a/src/Runner/Exception/ClassIsAbstractException.php b/src/Runner/Exception/ClassIsAbstractException.php new file mode 100644 index 00000000000..bf947589979 --- /dev/null +++ b/src/Runner/Exception/ClassIsAbstractException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ClassIsAbstractException extends RuntimeException implements Exception +{ + public function __construct(string $className, string $file) + { + parent::__construct( + sprintf( + 'Class %s declared in %s is abstract', + $className, + $file, + ), + ); + } +} diff --git a/src/Runner/Exception/DirectoryDoesNotExistException.php b/src/Runner/Exception/DirectoryDoesNotExistException.php new file mode 100644 index 00000000000..626c422567f --- /dev/null +++ b/src/Runner/Exception/DirectoryDoesNotExistException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DirectoryDoesNotExistException extends RuntimeException implements Exception +{ + public function __construct(string $directory) + { + parent::__construct( + sprintf( + 'Directory "%s" does not exist and could not be created', + $directory, + ), + ); + } +} diff --git a/src/Runner/Exception/ErrorException.php b/src/Runner/Exception/ErrorException.php new file mode 100644 index 00000000000..954684e9fac --- /dev/null +++ b/src/Runner/Exception/ErrorException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use Error; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ErrorException extends Error implements Exception +{ +} diff --git a/src/Runner/Exception/Exception.php b/src/Runner/Exception/Exception.php new file mode 100644 index 00000000000..ea0cf4244d3 --- /dev/null +++ b/src/Runner/Exception/Exception.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\Exception +{ +} diff --git a/src/Runner/Exception/FileDoesNotExistException.php b/src/Runner/Exception/FileDoesNotExistException.php new file mode 100644 index 00000000000..5b84c785d5b --- /dev/null +++ b/src/Runner/Exception/FileDoesNotExistException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FileDoesNotExistException extends RuntimeException implements Exception +{ + public function __construct(string $file) + { + parent::__construct( + sprintf( + 'File "%s" does not exist', + $file, + ), + ); + } +} diff --git a/src/Runner/Exception/InvalidOrderException.php b/src/Runner/Exception/InvalidOrderException.php new file mode 100644 index 00000000000..016ec85e457 --- /dev/null +++ b/src/Runner/Exception/InvalidOrderException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidOrderException extends RuntimeException implements Exception +{ +} diff --git a/src/Runner/Exception/ParameterDoesNotExistException.php b/src/Runner/Exception/ParameterDoesNotExistException.php new file mode 100644 index 00000000000..5d7a096754a --- /dev/null +++ b/src/Runner/Exception/ParameterDoesNotExistException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ParameterDoesNotExistException extends RuntimeException implements Exception +{ + public function __construct(string $name) + { + parent::__construct( + sprintf( + 'Parameter "%s" does not exist', + $name, + ), + ); + } +} diff --git a/src/Runner/Extension/Extension.php b/src/Runner/Extension/Extension.php new file mode 100644 index 00000000000..35610bc3d6a --- /dev/null +++ b/src/Runner/Extension/Extension.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use PHPUnit\TextUI\Configuration\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +interface Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void; +} diff --git a/src/Runner/Extension/ExtensionBootstrapper.php b/src/Runner/Extension/ExtensionBootstrapper.php new file mode 100644 index 00000000000..89966aec0aa --- /dev/null +++ b/src/Runner/Extension/ExtensionBootstrapper.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use const PHP_EOL; +use function assert; +use function class_exists; +use function class_implements; +use function in_array; +use function sprintf; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\TextUI\Configuration\Configuration; +use ReflectionClass; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExtensionBootstrapper +{ + private Configuration $configuration; + private Facade $facade; + + public function __construct(Configuration $configuration, Facade $facade) + { + $this->configuration = $configuration; + $this->facade = $facade; + } + + /** + * @param non-empty-string $className + * @param array $parameters + */ + public function bootstrap(string $className, array $parameters): void + { + if (!class_exists($className)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot bootstrap extension because class %s does not exist', + $className, + ), + ); + + return; + } + + if (!in_array(Extension::class, class_implements($className), true)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot bootstrap extension because class %s does not implement interface %s', + $className, + Extension::class, + ), + ); + + return; + } + + try { + $instance = new ReflectionClass($className)->newInstance(); + + assert($instance instanceof Extension); + + $instance->bootstrap( + $this->configuration, + $this->facade, + ParameterCollection::fromArray($parameters), + ); + } catch (Throwable $t) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Bootstrapping of extension %s failed: %s%s%s', + $className, + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString(), + ), + ); + + return; + } + + EventFacade::emitter()->testRunnerBootstrappedExtension( + $className, + $parameters, + ); + } +} diff --git a/src/Runner/Extension/Facade.php b/src/Runner/Extension/Facade.php new file mode 100644 index 00000000000..910f4e5fe13 --- /dev/null +++ b/src/Runner/Extension/Facade.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\Subscriber; +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Event\UnknownSubscriberTypeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private bool $replacesOutput = false; + private bool $replacesProgressOutput = false; + private bool $replacesResultOutput = false; + private bool $requiresCodeCoverageCollection = false; + + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscribers(Subscriber ...$subscribers): void + { + EventFacade::instance()->registerSubscribers(...$subscribers); + } + + /** + * @throws EventFacadeIsSealedException + * @throws UnknownSubscriberTypeException + */ + public function registerSubscriber(Subscriber $subscriber): void + { + EventFacade::instance()->registerSubscriber($subscriber); + } + + /** + * @throws EventFacadeIsSealedException + */ + public function registerTracer(Tracer $tracer): void + { + EventFacade::instance()->registerTracer($tracer); + } + + public function replaceOutput(): void + { + $this->replacesOutput = true; + } + + public function replacesOutput(): bool + { + return $this->replacesOutput; + } + + public function replaceProgressOutput(): void + { + $this->replacesProgressOutput = true; + } + + public function replacesProgressOutput(): bool + { + return $this->replacesOutput || $this->replacesProgressOutput; + } + + public function replaceResultOutput(): void + { + $this->replacesResultOutput = true; + } + + public function replacesResultOutput(): bool + { + return $this->replacesOutput || $this->replacesResultOutput; + } + + public function requireCodeCoverageCollection(): void + { + $this->requiresCodeCoverageCollection = true; + } + + public function requiresCodeCoverageCollection(): bool + { + return $this->requiresCodeCoverageCollection; + } +} diff --git a/src/Runner/Extension/ParameterCollection.php b/src/Runner/Extension/ParameterCollection.php new file mode 100644 index 00000000000..fef1c9b1ae6 --- /dev/null +++ b/src/Runner/Extension/ParameterCollection.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use function array_key_exists; +use PHPUnit\Runner\ParameterDoesNotExistException; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ParameterCollection +{ + /** + * @var array + */ + private array $parameters; + + /** + * @param array $parameters + */ + public static function fromArray(array $parameters): self + { + return new self($parameters); + } + + /** + * @param array $parameters + */ + private function __construct(array $parameters) + { + $this->parameters = $parameters; + } + + public function has(string $name): bool + { + return array_key_exists($name, $this->parameters); + } + + /** + * @throws ParameterDoesNotExistException + */ + public function get(string $name): string + { + if (!$this->has($name)) { + throw new ParameterDoesNotExistException($name); + } + + return $this->parameters[$name]; + } +} diff --git a/src/Runner/Extension/PharLoader.php b/src/Runner/Extension/PharLoader.php new file mode 100644 index 00000000000..7f3c4b44914 --- /dev/null +++ b/src/Runner/Extension/PharLoader.php @@ -0,0 +1,149 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Extension; + +use function count; +use function explode; +use function extension_loaded; +use function implode; +use function is_file; +use function sprintf; +use function str_contains; +use PharIo\Manifest\ApplicationName; +use PharIo\Manifest\Exception as ManifestException; +use PharIo\Manifest\ManifestLoader; +use PharIo\Version\Version as PharIoVersion; +use PHPUnit\Event; +use PHPUnit\Runner\Version; +use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PharLoader +{ + /** + * @param non-empty-string $directory + * + * @return list + */ + public function loadPharExtensionsInDirectory(string $directory): array + { + $pharExtensionLoaded = extension_loaded('phar'); + $loadedExtensions = []; + + foreach ((new FileIteratorFacade)->getFilesAsArray($directory, '.phar') as $file) { + if (!$pharExtensionLoaded) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot load extension from %s because the PHAR extension is not available', + $file, + ), + ); + + continue; + } + + if (!is_file('phar://' . $file . '/manifest.xml')) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s is not an extension for PHPUnit', + $file, + ), + ); + + continue; + } + + try { + $applicationName = new ApplicationName('phpunit/phpunit'); + $version = new PharIoVersion($this->phpunitVersion()); + $manifest = ManifestLoader::fromFile('phar://' . $file . '/manifest.xml'); + + if (!$manifest->isExtensionFor($applicationName)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s is not an extension for PHPUnit', + $file, + ), + ); + + continue; + } + + if (!$manifest->isExtensionFor($applicationName, $version)) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s is not compatible with PHPUnit %s', + $file, + Version::series(), + ), + ); + + continue; + } + } catch (ManifestException $e) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot load extension from %s: %s', + $file, + $e->getMessage(), + ), + ); + + continue; + } + + try { + @require $file; + } catch (Throwable $t) { + Event\Facade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot load extension from %s: %s', + $file, + $t->getMessage(), + ), + ); + + continue; + } + + $loadedExtensions[] = $manifest->getName()->asString() . ' ' . $manifest->getVersion()->getVersionString(); + + Event\Facade::emitter()->testRunnerLoadedExtensionFromPhar( + $file, + $manifest->getName()->asString(), + $manifest->getVersion()->getVersionString(), + ); + } + + return $loadedExtensions; + } + + private function phpunitVersion(): string + { + $version = Version::id(); + + if (!str_contains($version, '-')) { + return $version; + } + + $parts = explode('.', explode('-', $version)[0]); + + if (count($parts) === 2) { + $parts[] = 0; + } + + return implode('.', $parts); + } +} diff --git a/src/Runner/Filter/ExcludeGroupFilterIterator.php b/src/Runner/Filter/ExcludeGroupFilterIterator.php new file mode 100644 index 00000000000..45296b2d199 --- /dev/null +++ b/src/Runner/Filter/ExcludeGroupFilterIterator.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeGroupFilterIterator extends GroupFilterIterator +{ + /** + * @param non-empty-string $id + * @param list $groupTests + */ + protected function doAccept(string $id, array $groupTests): bool + { + return !in_array($id, $groupTests, true); + } +} diff --git a/src/Runner/Filter/ExcludeNameFilterIterator.php b/src/Runner/Filter/ExcludeNameFilterIterator.php new file mode 100644 index 00000000000..ff8459312ef --- /dev/null +++ b/src/Runner/Filter/ExcludeNameFilterIterator.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeNameFilterIterator extends NameFilterIterator +{ + protected function doAccept(bool $result): bool + { + return !$result; + } +} diff --git a/src/Runner/Filter/Factory.php b/src/Runner/Filter/Factory.php new file mode 100644 index 00000000000..0335e25b5bd --- /dev/null +++ b/src/Runner/Filter/Factory.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function assert; +use FilterIterator; +use Iterator; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestSuite; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Factory +{ + /** + * @var list>>, argument: list|non-empty-string}> + */ + private array $filters = []; + + /** + * @param list $testIds + */ + public function addTestIdFilter(array $testIds): void + { + $this->filters[] = [ + 'className' => TestIdFilterIterator::class, + 'argument' => $testIds, + ]; + } + + /** + * @param list $groups + */ + public function addIncludeGroupFilter(array $groups): void + { + $this->filters[] = [ + 'className' => IncludeGroupFilterIterator::class, + 'argument' => $groups, + ]; + } + + /** + * @param list $groups + */ + public function addExcludeGroupFilter(array $groups): void + { + $this->filters[] = [ + 'className' => ExcludeGroupFilterIterator::class, + 'argument' => $groups, + ]; + } + + /** + * @param non-empty-string $name + */ + public function addIncludeNameFilter(string $name): void + { + $this->filters[] = [ + 'className' => IncludeNameFilterIterator::class, + 'argument' => $name, + ]; + } + + /** + * @param non-empty-string $name + */ + public function addExcludeNameFilter(string $name): void + { + $this->filters[] = [ + 'className' => ExcludeNameFilterIterator::class, + 'argument' => $name, + ]; + } + + /** + * @param Iterator $iterator + * + * @return FilterIterator> + */ + public function factory(Iterator $iterator, TestSuite $suite): FilterIterator + { + foreach ($this->filters as $filter) { + $iterator = new $filter['className']( + $iterator, + $filter['argument'], + $suite, + ); + } + + assert($iterator instanceof FilterIterator); + + return $iterator; + } +} diff --git a/src/Runner/Filter/GroupFilterIterator.php b/src/Runner/Filter/GroupFilterIterator.php new file mode 100644 index 00000000000..da45211d752 --- /dev/null +++ b/src/Runner/Filter/GroupFilterIterator.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function array_merge; +use function array_push; +use function in_array; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class GroupFilterIterator extends RecursiveFilterIterator +{ + /** + * @var list + */ + private readonly array $groupTests; + + /** + * @param RecursiveIterator $iterator + * @param list $groups + */ + public function __construct(RecursiveIterator $iterator, array $groups, TestSuite $suite) + { + parent::__construct($iterator); + + $groupTests = []; + + foreach ($suite->groups() as $group => $tests) { + if (in_array($group, $groups, true)) { + $groupTests = array_merge($groupTests, $tests); + + array_push($groupTests, ...$groupTests); + } + } + + $this->groupTests = $groupTests; + } + + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + + if ($test instanceof TestSuite) { + return true; + } + + if ($test instanceof TestCase || $test instanceof PhptTestCase) { + return $this->doAccept($test->valueObjectForEvents()->id(), $this->groupTests); + } + + return true; + } + + /** + * @param non-empty-string $id + * @param list $groupTests + */ + abstract protected function doAccept(string $id, array $groupTests): bool; +} diff --git a/src/Runner/Filter/IncludeGroupFilterIterator.php b/src/Runner/Filter/IncludeGroupFilterIterator.php new file mode 100644 index 00000000000..afdaefda9fd --- /dev/null +++ b/src/Runner/Filter/IncludeGroupFilterIterator.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncludeGroupFilterIterator extends GroupFilterIterator +{ + /** + * @param non-empty-string $id + * @param list $groupTests + */ + protected function doAccept(string $id, array $groupTests): bool + { + return in_array($id, $groupTests, true); + } +} diff --git a/src/Runner/Filter/IncludeNameFilterIterator.php b/src/Runner/Filter/IncludeNameFilterIterator.php new file mode 100644 index 00000000000..9bca65eb2ba --- /dev/null +++ b/src/Runner/Filter/IncludeNameFilterIterator.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class IncludeNameFilterIterator extends NameFilterIterator +{ + protected function doAccept(bool $result): bool + { + return $result; + } +} diff --git a/src/Runner/Filter/NameFilterIterator.php b/src/Runner/Filter/NameFilterIterator.php new file mode 100644 index 00000000000..a2fc69b3d36 --- /dev/null +++ b/src/Runner/Filter/NameFilterIterator.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function end; +use function preg_match; +use function sprintf; +use function substr; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract class NameFilterIterator extends RecursiveFilterIterator +{ + /** + * @var non-empty-string + */ + private readonly string $regularExpression; + private readonly ?int $dataSetMinimum; + private readonly ?int $dataSetMaximum; + + /** + * @param RecursiveIterator $iterator + * @param non-empty-string $filter + */ + public function __construct(RecursiveIterator $iterator, string $filter) + { + parent::__construct($iterator); + + $preparedFilter = $this->prepareFilter($filter); + + $this->regularExpression = $preparedFilter['regularExpression']; + $this->dataSetMinimum = $preparedFilter['dataSetMinimum']; + $this->dataSetMaximum = $preparedFilter['dataSetMaximum']; + } + + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + + if ($test instanceof TestSuite) { + return true; + } + + if ($test instanceof PhptTestCase) { + return false; + } + + $name = $test::class . '::' . $test->nameWithDataSet(); + + $accepted = @preg_match($this->regularExpression, $name, $matches) === 1; + + if ($accepted && isset($this->dataSetMaximum)) { + $set = end($matches); + $accepted = $set >= $this->dataSetMinimum && $set <= $this->dataSetMaximum; + } + + return $this->doAccept($accepted); + } + + abstract protected function doAccept(bool $result): bool; + + /** + * @param non-empty-string $filter + * + * @return array{regularExpression: non-empty-string, dataSetMinimum: ?int, dataSetMaximum: ?int} + */ + private function prepareFilter(string $filter): array + { + $dataSetMinimum = null; + $dataSetMaximum = null; + + if (preg_match('/[a-zA-Z0-9]/', substr($filter, 0, 1)) === 1 || @preg_match($filter, '') === false) { + // Handles: + // * testAssertEqualsSucceeds#4 + // * testAssertEqualsSucceeds#4-8 + if (preg_match('/^(.*?)#(\d+)(?:-(\d+))?$/', $filter, $matches)) { + if (isset($matches[3]) && $matches[2] < $matches[3]) { + $filter = sprintf( + '%s.*with data set #(\d+)$', + $matches[1], + ); + + $dataSetMinimum = (int) $matches[2]; + $dataSetMaximum = (int) $matches[3]; + } else { + $filter = sprintf( + '%s.*with data set #%s$', + $matches[1], + $matches[2], + ); + } + } // Handles: + // * testDetermineJsonError@JSON_ERROR_NONE + // * testDetermineJsonError@JSON.* + elseif (preg_match('/^(.*?)@(.+)$/', $filter, $matches)) { + $filter = sprintf( + '%s.*with data set "%s"$', + $matches[1], + $matches[2], + ); + } + + // Do NOT use preg_quote, to keep magic characters. + $filter = sprintf( + '{%s}i', + $filter, + ); + } + + return [ + 'regularExpression' => $filter, + 'dataSetMinimum' => $dataSetMinimum, + 'dataSetMaximum' => $dataSetMaximum, + ]; + } +} diff --git a/src/Runner/Filter/TestIdFilterIterator.php b/src/Runner/Filter/TestIdFilterIterator.php new file mode 100644 index 00000000000..1180de4e780 --- /dev/null +++ b/src/Runner/Filter/TestIdFilterIterator.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function in_array; +use PHPUnit\Event\TestData\NoDataSetFromDataProviderException; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use RecursiveFilterIterator; +use RecursiveIterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestIdFilterIterator extends RecursiveFilterIterator +{ + /** + * @var non-empty-list + */ + private readonly array $testIds; + + /** + * @param RecursiveIterator $iterator + * @param non-empty-list $testIds + */ + public function __construct(RecursiveIterator $iterator, array $testIds) + { + parent::__construct($iterator); + + $this->testIds = $testIds; + } + + public function accept(): bool + { + $test = $this->getInnerIterator()->current(); + + if ($test instanceof TestSuite) { + return true; + } + + if (!$test instanceof TestCase && !$test instanceof PhptTestCase) { + return false; + } + + try { + return in_array($test->valueObjectForEvents()->id(), $this->testIds, true); + } catch (NoDataSetFromDataProviderException) { + return false; + } + } +} diff --git a/src/Runner/GarbageCollection/GarbageCollectionHandler.php b/src/Runner/GarbageCollection/GarbageCollectionHandler.php new file mode 100644 index 00000000000..c6cd2dd3b1b --- /dev/null +++ b/src/Runner/GarbageCollection/GarbageCollectionHandler.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use function gc_collect_cycles; +use function gc_disable; +use function gc_enable; +use PHPUnit\Event\Facade; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class GarbageCollectionHandler +{ + private readonly Facade $facade; + private readonly int $threshold; + private int $tests = 0; + + public function __construct(Facade $facade, int $threshold) + { + $this->facade = $facade; + $this->threshold = $threshold; + + $this->registerSubscribers(); + } + + public function executionStarted(): void + { + gc_disable(); + + $this->facade->emitter()->testRunnerDisabledGarbageCollection(); + + gc_collect_cycles(); + + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + } + + public function executionFinished(): void + { + gc_collect_cycles(); + + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + + gc_enable(); + + $this->facade->emitter()->testRunnerEnabledGarbageCollection(); + } + + public function testFinished(): void + { + $this->tests++; + + if ($this->tests === $this->threshold) { + gc_collect_cycles(); + + $this->facade->emitter()->testRunnerTriggeredGarbageCollection(); + + $this->tests = 0; + } + } + + private function registerSubscribers(): void + { + $this->facade->registerSubscribers( + new ExecutionStartedSubscriber($this), + new ExecutionFinishedSubscriber($this), + new TestFinishedSubscriber($this), + ); + } +} diff --git a/src/Runner/GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php b/src/Runner/GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..4ff8e11357e --- /dev/null +++ b/src/Runner/GarbageCollection/Subscriber/ExecutionFinishedSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber as TestRunnerExecutionFinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionFinishedSubscriber extends Subscriber implements TestRunnerExecutionFinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(ExecutionFinished $event): void + { + $this->handler()->executionFinished(); + } +} diff --git a/src/Runner/GarbageCollection/Subscriber/ExecutionStartedSubscriber.php b/src/Runner/GarbageCollection/Subscriber/ExecutionStartedSubscriber.php new file mode 100644 index 00000000000..1b99b8b72eb --- /dev/null +++ b/src/Runner/GarbageCollection/Subscriber/ExecutionStartedSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStartedSubscriber extends Subscriber implements TestRunnerExecutionStartedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(ExecutionStarted $event): void + { + $this->handler()->executionStarted(); + } +} diff --git a/src/Runner/GarbageCollection/Subscriber/Subscriber.php b/src/Runner/GarbageCollection/Subscriber/Subscriber.php new file mode 100644 index 00000000000..3c9abce8d70 --- /dev/null +++ b/src/Runner/GarbageCollection/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private GarbageCollectionHandler $handler; + + public function __construct(GarbageCollectionHandler $handler) + { + $this->handler = $handler; + } + + protected function handler(): GarbageCollectionHandler + { + return $this->handler; + } +} diff --git a/src/Runner/GarbageCollection/Subscriber/TestFinishedSubscriber.php b/src/Runner/GarbageCollection/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..4ffae389fbc --- /dev/null +++ b/src/Runner/GarbageCollection/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\GarbageCollection; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->handler()->testFinished(); + } +} diff --git a/src/Runner/HookMethod/HookMethod.php b/src/Runner/HookMethod/HookMethod.php new file mode 100644 index 00000000000..2442f75ecac --- /dev/null +++ b/src/Runner/HookMethod/HookMethod.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class HookMethod +{ + /** + * @var non-empty-string + */ + private string $methodName; + private int $priority; + + /** + * @param non-empty-string $methodName + */ + public function __construct(string $methodName, int $priority) + { + $this->methodName = $methodName; + $this->priority = $priority; + } + + /** + * @return non-empty-string + */ + public function methodName(): string + { + return $this->methodName; + } + + public function priority(): int + { + return $this->priority; + } +} diff --git a/src/Runner/HookMethod/HookMethodCollection.php b/src/Runner/HookMethod/HookMethodCollection.php new file mode 100644 index 00000000000..a3593fd5fd3 --- /dev/null +++ b/src/Runner/HookMethod/HookMethodCollection.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_map; +use function usort; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class HookMethodCollection +{ + private readonly bool $shouldPrepend; + + /** + * @var non-empty-list + */ + private array $hookMethods; + + public static function defaultBeforeClass(): self + { + return new self(new HookMethod('setUpBeforeClass', 0), true); + } + + public static function defaultBefore(): self + { + return new self(new HookMethod('setUp', 0), true); + } + + public static function defaultPreCondition(): self + { + return new self(new HookMethod('assertPreConditions', 0), true); + } + + public static function defaultPostCondition(): self + { + return new self(new HookMethod('assertPostConditions', 0), false); + } + + public static function defaultAfter(): self + { + return new self(new HookMethod('tearDown', 0), false); + } + + public static function defaultAfterClass(): self + { + return new self(new HookMethod('tearDownAfterClass', 0), false); + } + + private function __construct(HookMethod $default, bool $shouldPrepend) + { + $this->hookMethods = [$default]; + $this->shouldPrepend = $shouldPrepend; + } + + public function add(HookMethod $hookMethod): self + { + if ($this->shouldPrepend) { + $this->hookMethods = [$hookMethod, ...$this->hookMethods]; + } else { + $this->hookMethods[] = $hookMethod; + } + + return $this; + } + + /** + * @return list + */ + public function methodNamesSortedByPriority(): array + { + $hookMethods = $this->hookMethods; + + usort($hookMethods, static fn (HookMethod $a, HookMethod $b) => $b->priority() <=> $a->priority()); + + return array_map( + static fn (HookMethod $hookMethod) => $hookMethod->methodName(), + $hookMethods, + ); + } +} diff --git a/src/Runner/IssueFilter.php b/src/Runner/IssueFilter.php new file mode 100644 index 00000000000..445c15b7f79 --- /dev/null +++ b/src/Runner/IssueFilter.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IssueFilter +{ + private Source $source; + + public function __construct(Source $source) + { + $this->source = $source; + } + + public function shouldBeProcessed(DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event, bool $onlyTestMethods = false): bool + { + if ($onlyTestMethods && !$event->test()->isTestMethod()) { + return false; + } + + if ($event instanceof DeprecationTriggered || $event instanceof PhpDeprecationTriggered) { + if ($event->ignoredByTest()) { + return false; + } + + if ($this->source->ignoreSelfDeprecations() && + ($event->trigger()->isTest() || $event->trigger()->isSelf())) { + return false; + } + + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return false; + } + + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return false; + } + + if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { + return false; + } + } + + if ($event instanceof NoticeTriggered) { + if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { + return false; + } + + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return false; + } + } + + if ($event instanceof PhpNoticeTriggered) { + if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { + return false; + } + + if ($this->source->restrictNotices() && !SourceFilter::instance()->includes($event->file())) { + return false; + } + } + + if ($event instanceof WarningTriggered) { + if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { + return false; + } + + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return false; + } + } + + if ($event instanceof PhpWarningTriggered) { + if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { + return false; + } + + if ($this->source->restrictWarnings() && !SourceFilter::instance()->includes($event->file())) { + return false; + } + } + + if ($event instanceof ErrorTriggered) { + if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { + return false; + } + } + + return true; + } +} diff --git a/src/Runner/Phpt/Exception/InvalidPhptFileException.php b/src/Runner/Phpt/Exception/InvalidPhptFileException.php new file mode 100644 index 00000000000..07a2953ec54 --- /dev/null +++ b/src/Runner/Phpt/Exception/InvalidPhptFileException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidPhptFileException extends RuntimeException implements RunnerException +{ +} diff --git a/src/Runner/Phpt/Exception/PhptExternalFileCannotBeLoadedException.php b/src/Runner/Phpt/Exception/PhptExternalFileCannotBeLoadedException.php new file mode 100644 index 00000000000..bdee6262219 --- /dev/null +++ b/src/Runner/Phpt/Exception/PhptExternalFileCannotBeLoadedException.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function sprintf; +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhptExternalFileCannotBeLoadedException extends RuntimeException implements RunnerException +{ + public function __construct(string $section, string $file) + { + parent::__construct( + sprintf( + 'Could not load --%s-- %s for PHPT file', + $section . '_EXTERNAL', + $file, + ), + ); + } +} diff --git a/src/Runner/Phpt/Exception/UnsupportedPhptSectionException.php b/src/Runner/Phpt/Exception/UnsupportedPhptSectionException.php new file mode 100644 index 00000000000..9079f9967cc --- /dev/null +++ b/src/Runner/Phpt/Exception/UnsupportedPhptSectionException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function sprintf; +use PHPUnit\Runner\Exception as RunnerException; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class UnsupportedPhptSectionException extends RuntimeException implements RunnerException +{ + public function __construct(string $section) + { + parent::__construct( + sprintf( + 'PHPUnit does not support PHPT --%s-- sections', + $section, + ), + ); + } +} diff --git a/src/Runner/Phpt/Parser.php b/src/Runner/Phpt/Parser.php new file mode 100644 index 00000000000..72582d733ee --- /dev/null +++ b/src/Runner/Phpt/Parser.php @@ -0,0 +1,213 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function dirname; +use function explode; +use function file; +use function file_get_contents; +use function is_file; +use function is_readable; +use function is_string; +use function preg_match; +use function rtrim; +use function str_contains; +use function trim; +use PHPUnit\Runner\Exception; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class Parser +{ + /** + * @param non-empty-string $phptFile + * + * @throws Exception + * + * @return array + */ + public function parse(string $phptFile): array + { + $sections = []; + $section = ''; + + $unsupportedSections = [ + 'CGI', + 'COOKIE', + 'DEFLATE_POST', + 'EXPECTHEADERS', + 'EXTENSIONS', + 'GET', + 'GZIP_POST', + 'HEADERS', + 'PHPDBG', + 'POST', + 'POST_RAW', + 'PUT', + 'REDIRECTTEST', + 'REQUEST', + ]; + + $lineNr = 0; + + foreach (file($phptFile) as $line) { + $lineNr++; + + if (preg_match('/^--([_A-Z]+)--/', $line, $result)) { + $section = $result[1]; + $sections[$section] = ''; + $sections[$section . '_offset'] = $lineNr; + + continue; + } + + if ($section === '') { + throw new InvalidPhptFileException; + } + + $sections[$section] .= $line; + } + + if (isset($sections['FILEEOF'])) { + $sections['FILE'] = rtrim($sections['FILEEOF'], "\r\n"); + + unset($sections['FILEEOF']); + } + + $this->parseExternal($phptFile, $sections); + $this->validate($sections); + + foreach ($unsupportedSections as $unsupportedSection) { + if (isset($sections[$unsupportedSection])) { + throw new UnsupportedPhptSectionException($unsupportedSection); + } + } + + return $sections; + } + + /** + * @return array + */ + public function parseEnvSection(string $content): array + { + $env = []; + + foreach (explode("\n", trim($content)) as $e) { + $e = explode('=', trim($e), 2); + + if ($e[0] !== '' && isset($e[1])) { + $env[$e[0]] = $e[1]; + } + } + + return $env; + } + + /** + * @param array|string $content + * @param array|non-empty-string> $ini + * + * @return array|non-empty-string> + */ + public function parseIniSection(array|string $content, array $ini = []): array + { + if (is_string($content)) { + $content = explode("\n", trim($content)); + } + + foreach ($content as $setting) { + if (!str_contains($setting, '=')) { + continue; + } + + $setting = explode('=', $setting, 2); + $name = trim($setting[0]); + $value = trim($setting[1]); + + if ($name === 'extension' || $name === 'zend_extension') { + if (!isset($ini[$name])) { + $ini[$name] = []; + } + + $ini[$name][] = $value; + + continue; + } + + $ini[$name] = $value; + } + + return $ini; + } + + /** + * @param non-empty-string $phptFile + * @param array $sections + * + * @throws Exception + */ + private function parseExternal(string $phptFile, array &$sections): void + { + $allowSections = [ + 'FILE', + 'EXPECT', + 'EXPECTF', + 'EXPECTREGEX', + ]; + + $testDirectory = dirname($phptFile) . DIRECTORY_SEPARATOR; + + foreach ($allowSections as $section) { + if (isset($sections[$section . '_EXTERNAL'])) { + $externalFilename = trim($sections[$section . '_EXTERNAL']); + + if (!is_file($testDirectory . $externalFilename) || + !is_readable($testDirectory . $externalFilename)) { + throw new PhptExternalFileCannotBeLoadedException( + $section, + $testDirectory . $externalFilename, + ); + } + + $contents = file_get_contents($testDirectory . $externalFilename); + + assert($contents !== false && $contents !== ''); + + $sections[$section] = $contents; + } + } + } + + /** + * @param array $sections + * + * @throws InvalidPhptFileException + */ + private function validate(array $sections): void + { + if (!isset($sections['FILE'])) { + throw new InvalidPhptFileException; + } + + if (!isset($sections['EXPECT']) && + !isset($sections['EXPECTF']) && + !isset($sections['EXPECTREGEX'])) { + throw new InvalidPhptFileException; + } + } +} diff --git a/src/Runner/Phpt/Renderer.php b/src/Runner/Phpt/Renderer.php new file mode 100644 index 00000000000..0fe1de925e7 --- /dev/null +++ b/src/Runner/Phpt/Renderer.php @@ -0,0 +1,110 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function assert; +use function defined; +use function dirname; +use function file_put_contents; +use function str_replace; +use function var_export; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use SebastianBergmann\Template\InvalidArgumentException; +use SebastianBergmann\Template\Template; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class Renderer +{ + /** + * @param non-empty-string $phptFile + * @param non-empty-string $code + * + * @return non-empty-string + */ + public function render(string $phptFile, string $code): string + { + return str_replace( + [ + '__DIR__', + '__FILE__', + ], + [ + "'" . dirname($phptFile) . "'", + "'" . $phptFile . "'", + ], + $code, + ); + } + + /** + * @param non-empty-string $job + * @param array{coverage: non-empty-string, job: non-empty-string} $files + * + * @param-out non-empty-string $job + * + * @throws InvalidArgumentException + */ + public function renderForCoverage(string &$job, bool $pathCoverage, ?string $codeCoverageCacheDirectory, array $files): void + { + $template = new Template( + __DIR__ . '/templates/phpt.tpl', + ); + + $composerAutoload = '\'\''; + + if (defined('PHPUNIT_COMPOSER_INSTALL')) { + $composerAutoload = var_export(PHPUNIT_COMPOSER_INSTALL, true); + } + + $phar = '\'\''; + + if (defined('__PHPUNIT_PHAR__')) { + $phar = var_export(__PHPUNIT_PHAR__, true); + } + + if ($codeCoverageCacheDirectory === null) { + $codeCoverageCacheDirectory = 'null'; + } else { + $codeCoverageCacheDirectory = "'" . $codeCoverageCacheDirectory . "'"; + } + + $bootstrap = ''; + + if (ConfigurationRegistry::get()->hasBootstrap()) { + $bootstrap = ConfigurationRegistry::get()->bootstrap(); + } + + $template->setVar( + [ + 'bootstrap' => $bootstrap, + 'composerAutoload' => $composerAutoload, + 'phar' => $phar, + 'job' => $files['job'], + 'coverageFile' => $files['coverage'], + 'driverMethod' => $pathCoverage ? 'forLineAndPathCoverage' : 'forLineCoverage', + 'codeCoverageCacheDirectory' => $codeCoverageCacheDirectory, + ], + ); + + file_put_contents($files['job'], $job); + + $rendered = $template->render(); + + assert($rendered !== ''); + + $job = $rendered; + } +} diff --git a/src/Runner/Phpt/TestCase.php b/src/Runner/Phpt/TestCase.php new file mode 100644 index 00000000000..ab75397b20a --- /dev/null +++ b/src/Runner/Phpt/TestCase.php @@ -0,0 +1,709 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const DIRECTORY_SEPARATOR; +use function array_merge; +use function basename; +use function debug_backtrace; +use function dirname; +use function explode; +use function extension_loaded; +use function file_get_contents; +use function is_array; +use function is_file; +use function ltrim; +use function ob_get_clean; +use function ob_start; +use function preg_match; +use function preg_replace; +use function preg_split; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function strncasecmp; +use function substr; +use function trim; +use function unlink; +use function unserialize; +use PHPUnit\Event\Code\Phpt; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\AssertionFailedError; +use PHPUnit\Framework\ExecutionOrderDependency; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\IncompleteTestError; +use PHPUnit\Framework\PhptAssertionFailedError; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Framework\Test; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\Exception; +use PHPUnit\Util\PHP\Job; +use PHPUnit\Util\PHP\JobRunnerRegistry; +use SebastianBergmann\CodeCoverage\Data\RawCodeCoverageData; +use SebastianBergmann\CodeCoverage\InvalidArgumentException; +use SebastianBergmann\CodeCoverage\ReflectionException; +use SebastianBergmann\CodeCoverage\Test\TestSize\TestSize; +use SebastianBergmann\CodeCoverage\Test\TestStatus\TestStatus; +use SebastianBergmann\CodeCoverage\TestIdMissingException; +use SebastianBergmann\CodeCoverage\UnintentionallyCoveredCodeException; +use staabm\SideEffectsDetector\SideEffect; +use staabm\SideEffectsDetector\SideEffectsDetector; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @see https://qa.php.net/phpt_details.php + */ +final readonly class TestCase implements Reorderable, SelfDescribing, Test +{ + /** + * @var non-empty-string + */ + private string $filename; + + /** + * @param non-empty-string $filename + */ + public function __construct(string $filename) + { + $this->filename = $filename; + } + + public function count(): int + { + return 1; + } + + /** + * @throws \PHPUnit\Framework\Exception + * @throws \SebastianBergmann\Template\InvalidArgumentException + * @throws Exception + * @throws InvalidArgumentException + * @throws NoPreviousThrowableException + * @throws ReflectionException + * @throws TestIdMissingException + * @throws UnintentionallyCoveredCodeException + */ + public function run(): void + { + $emitter = EventFacade::emitter(); + $parser = new Parser; + + $emitter->testPreparationStarted( + $this->valueObjectForEvents(), + ); + + try { + $sections = $parser->parse($this->filename); + } catch (Exception $e) { + $emitter->testPrepared($this->valueObjectForEvents()); + $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($e)); + $emitter->testFinished($this->valueObjectForEvents(), 0); + + return; + } + + $code = (new Renderer)->render($this->filename, $sections['FILE']); + $xfail = false; + $environmentVariables = []; + $phpSettings = $parser->parseIniSection($this->settings(CodeCoverage::instance()->isActive())); + $input = null; + $arguments = []; + + $emitter->testPrepared($this->valueObjectForEvents()); + + if (isset($sections['INI'])) { + $phpSettings = $parser->parseIniSection($sections['INI'], $phpSettings); + } + + if (isset($sections['ENV'])) { + $environmentVariables = $parser->parseEnvSection($sections['ENV']); + } + + if ($this->shouldTestBeSkipped($sections, $phpSettings)) { + return; + } + + if (isset($sections['XFAIL'])) { + $xfail = trim($sections['XFAIL']); + } + + if (isset($sections['STDIN'])) { + $input = $sections['STDIN']; + } + + if (isset($sections['ARGS'])) { + $arguments = explode(' ', $sections['ARGS']); + } + + if (CodeCoverage::instance()->isActive()) { + $codeCoverageCacheDirectory = null; + + if (CodeCoverage::instance()->codeCoverage()->cachesStaticAnalysis()) { + $codeCoverageCacheDirectory = CodeCoverage::instance()->codeCoverage()->cacheDirectory(); + } + + (new Renderer)->renderForCoverage( + $code, + CodeCoverage::instance()->codeCoverage()->collectsBranchAndPathCoverage(), + $codeCoverageCacheDirectory, + $this->coverageFiles(), + ); + } + + $jobResult = JobRunnerRegistry::run( + new Job( + $code, + $this->stringifyIni($phpSettings), + $environmentVariables, + $arguments, + $input, + true, + ), + ); + + EventFacade::emitter()->childProcessFinished($jobResult->stdout(), $jobResult->stderr()); + + $output = $jobResult->stdout(); + + if (CodeCoverage::instance()->isActive()) { + $coverage = $this->cleanupForCoverage(); + + CodeCoverage::instance()->codeCoverage()->start($this->filename, TestSize::large()); + + CodeCoverage::instance()->codeCoverage()->append( + $coverage, + $this->filename, + true, + TestStatus::unknown(), + ); + } + + $passed = true; + + try { + $this->assertPhptExpectation($sections, $output); + } catch (AssertionFailedError $e) { + $failure = $e; + + if ($xfail !== false) { + $failure = new IncompleteTestError($xfail, 0, $e); + } elseif ($e instanceof ExpectationFailedException) { + $comparisonFailure = $e->getComparisonFailure(); + + if ($comparisonFailure !== null) { + $diff = $comparisonFailure->getDiff(); + } else { + $diff = $e->getMessage(); + } + + $hint = $this->locationHintFromDiff($diff, $sections); + $trace = array_merge($hint, debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS)); + $failure = new PhptAssertionFailedError( + $e->getMessage(), + 0, + (string) $trace[0]['file'], + (int) $trace[0]['line'], + $trace, + $comparisonFailure !== null ? $diff : '', + ); + } + + if ($failure instanceof IncompleteTestError) { + $emitter->testMarkedAsIncomplete($this->valueObjectForEvents(), ThrowableBuilder::from($failure)); + } else { + $emitter->testFailed($this->valueObjectForEvents(), ThrowableBuilder::from($failure), null); + } + + $passed = false; + } catch (Throwable $t) { + $emitter->testErrored($this->valueObjectForEvents(), ThrowableBuilder::from($t)); + + $passed = false; + } + + if ($passed) { + $emitter->testPassed($this->valueObjectForEvents()); + } + + $this->runClean($sections, CodeCoverage::instance()->isActive()); + + $emitter->testFinished($this->valueObjectForEvents(), 1); + } + + /** + * Returns the name of the test case. + */ + public function getName(): string + { + return $this->toString(); + } + + /** + * Returns a string representation of the test case. + */ + public function toString(): string + { + return $this->filename; + } + + public function sortId(): string + { + return $this->filename; + } + + /** + * @return list + */ + public function provides(): array + { + return []; + } + + /** + * @return list + */ + public function requires(): array + { + return []; + } + + /** + * @internal This method is not covered by the backward compatibility promise for PHPUnit + */ + public function valueObjectForEvents(): Phpt + { + return new Phpt($this->filename); + } + + /** + * @param array $sections + * + * @throws Exception + * @throws ExpectationFailedException + */ + private function assertPhptExpectation(array $sections, string $output): void + { + $assertions = [ + 'EXPECT' => 'assertEquals', + 'EXPECTF' => 'assertStringMatchesFormat', + 'EXPECTREGEX' => 'assertMatchesRegularExpression', + ]; + + $actual = preg_replace('/\r\n/', "\n", trim($output)); + + foreach ($assertions as $sectionName => $sectionAssertion) { + if (isset($sections[$sectionName])) { + $sectionContent = preg_replace('/\r\n/', "\n", trim($sections[$sectionName])); + $expected = $sectionName === 'EXPECTREGEX' ? "/{$sectionContent}/" : $sectionContent; + + /** @phpstan-ignore staticMethod.dynamicName */ + Assert::$sectionAssertion($expected, $actual); + + return; + } + } + + throw new InvalidPhptFileException; + } + + /** + * @param array $sections + * @param array|non-empty-string> $settings + */ + private function shouldTestBeSkipped(array $sections, array $settings): bool + { + if (!isset($sections['SKIPIF'])) { + return false; + } + + $skipIfCode = (new Renderer)->render($this->filename, $sections['SKIPIF']); + + if ($this->shouldRunInSubprocess($sections, $skipIfCode)) { + $jobResult = JobRunnerRegistry::run( + new Job( + $skipIfCode, + $this->stringifyIni($settings), + ), + ); + + $output = $jobResult->stdout(); + + EventFacade::emitter()->childProcessFinished($output, $jobResult->stderr()); + } else { + $output = $this->runCodeInLocalSandbox($skipIfCode); + } + + $this->triggerRunnerWarningOnPhpErrors('SKIPIF', $output); + + if (strncasecmp('skip', ltrim($output), 4) === 0) { + $message = ''; + + if (preg_match('/^\s*skip\s*(.+)\s*/i', $output, $skipMatch)) { + $message = substr($skipMatch[1], 2); + } + + EventFacade::emitter()->testSkipped( + $this->valueObjectForEvents(), + $message, + ); + + EventFacade::emitter()->testFinished($this->valueObjectForEvents(), 0); + + return true; + } + + return false; + } + + /** + * @param array $sections + */ + private function shouldRunInSubprocess(array $sections, string $cleanCode): bool + { + if (isset($sections['INI'])) { + // to get per-test INI settings, we need a dedicated subprocess + return true; + } + + $detector = new SideEffectsDetector; + $sideEffects = $detector->getSideEffects($cleanCode); + + if ($sideEffects === []) { + // no side-effects + return false; + } + + foreach ($sideEffects as $sideEffect) { + if ($sideEffect === SideEffect::STANDARD_OUTPUT) { + // stdout is fine, we will catch it using output-buffering + continue; + } + + if ($sideEffect === SideEffect::INPUT_OUTPUT) { + // IO is fine, as it doesn't pollute the main process + continue; + } + + return true; + } + + return false; + } + + private function runCodeInLocalSandbox(string $code): string + { + $code = preg_replace('/^<\?(?:php)?|\?>\s*+$/', '', $code); + $code = preg_replace('/declare\S?\([^)]+\)\S?;/', '', $code); + + // wrap in immediately invoked function to isolate local-side-effects of $code from our own process + $code = '(function() {' . $code . '})();'; + ob_start(); + @eval($code); + + return ob_get_clean(); + } + + /** + * @param array $sections + */ + private function runClean(array $sections, bool $collectCoverage): void + { + if (!isset($sections['CLEAN'])) { + return; + } + + $cleanCode = (new Renderer)->render($this->filename, $sections['CLEAN']); + + if ($this->shouldRunInSubprocess($sections, $cleanCode)) { + $jobResult = JobRunnerRegistry::run( + new Job( + $cleanCode, + $this->settings($collectCoverage), + ), + ); + + $output = $jobResult->stdout(); + + EventFacade::emitter()->childProcessFinished($jobResult->stdout(), $jobResult->stderr()); + } else { + $output = $this->runCodeInLocalSandbox($cleanCode); + } + + $this->triggerRunnerWarningOnPhpErrors('CLEAN', $output); + } + + /** + * @phpstan-ignore return.internalClass + */ + private function cleanupForCoverage(): RawCodeCoverageData + { + /** + * @phpstan-ignore staticMethod.internalClass + */ + $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); + $files = $this->coverageFiles(); + + $buffer = false; + + if (is_file($files['coverage'])) { + $buffer = @file_get_contents($files['coverage']); + } + + if ($buffer !== false) { + $coverage = @unserialize($buffer); + + if ($coverage === false) { + /** + * @phpstan-ignore staticMethod.internalClass + */ + $coverage = RawCodeCoverageData::fromXdebugWithoutPathCoverage([]); + } + } + + foreach ($files as $file) { + @unlink($file); + } + + return $coverage; + } + + /** + * @return array{coverage: non-empty-string, job: non-empty-string} + */ + private function coverageFiles(): array + { + $baseDir = dirname(realpath($this->filename)) . DIRECTORY_SEPARATOR; + $basename = basename($this->filename, 'phpt'); + + return [ + 'coverage' => $baseDir . $basename . 'coverage', + 'job' => $baseDir . $basename . 'php', + ]; + } + + /** + * @param array|non-empty-string> $ini + * + * @return list + */ + private function stringifyIni(array $ini): array + { + $settings = []; + + foreach ($ini as $key => $value) { + if (is_array($value)) { + foreach ($value as $val) { + $settings[] = $key . '=' . $val; + } + + continue; + } + + $settings[] = $key . '=' . $value; + } + + return $settings; + } + + /** + * @param array $sections + * + * @return non-empty-list + */ + private function locationHintFromDiff(string $message, array $sections): array + { + $needle = ''; + $previousLine = ''; + $block = 'message'; + + foreach (preg_split('/\r\n|\r|\n/', $message) as $line) { + $line = trim($line); + + if ($block === 'message' && $line === '--- Expected') { + $block = 'expected'; + } + + if ($block === 'expected' && $line === '@@ @@') { + $block = 'diff'; + } + + if ($block === 'diff') { + if (str_starts_with($line, '+')) { + $needle = $this->cleanDiffLine($previousLine); + + break; + } + + if (str_starts_with($line, '-')) { + $needle = $this->cleanDiffLine($line); + + break; + } + } + + if ($line !== '') { + $previousLine = $line; + } + } + + return $this->locationHint($needle, $sections); + } + + private function cleanDiffLine(string $line): string + { + if (preg_match('/^[\-+]([\'\"]?)(.*)\1$/', $line, $matches)) { + $line = $matches[2]; + } + + return $line; + } + + /** + * @param array $sections + * + * @return non-empty-list + */ + private function locationHint(string $needle, array $sections): array + { + $needle = trim($needle); + + if ($needle === '') { + return [[ + 'file' => realpath($this->filename), + 'line' => 1, + ]]; + } + + $search = [ + // 'FILE', + 'EXPECT', + 'EXPECTF', + 'EXPECTREGEX', + ]; + + foreach ($search as $section) { + if (!isset($sections[$section])) { + continue; + } + + if (isset($sections[$section . '_EXTERNAL'])) { + $externalFile = trim($sections[$section . '_EXTERNAL']); + + return [ + [ + 'file' => realpath(dirname($this->filename) . DIRECTORY_SEPARATOR . $externalFile), + 'line' => 1, + ], + [ + 'file' => realpath($this->filename), + 'line' => ($sections[$section . '_EXTERNAL_offset'] ?? 0) + 1, + ], + ]; + } + + $sectionOffset = $sections[$section . '_offset'] ?? 0; + $offset = $sectionOffset + 1; + + foreach (preg_split('/\r\n|\r|\n/', $sections[$section]) as $line) { + if (str_contains($line, $needle)) { + return [ + [ + 'file' => realpath($this->filename), + 'line' => $offset, + ], + ]; + } + + $offset++; + } + } + + return [ + [ + 'file' => realpath($this->filename), + 'line' => 1, + ], + ]; + } + + /** + * @return list + */ + private function settings(bool $collectCoverage): array + { + $settings = [ + 'allow_url_fopen=1', + 'auto_append_file=', + 'auto_prepend_file=', + 'disable_functions=', + 'display_errors=1', + 'docref_ext=.html', + 'docref_root=', + 'error_append_string=', + 'error_prepend_string=', + 'error_reporting=-1', + 'html_errors=0', + 'log_errors=0', + 'open_basedir=', + 'output_buffering=Off', + 'output_handler=', + 'report_zend_debug=0', + ]; + + if (extension_loaded('pcov')) { + if ($collectCoverage) { + $settings[] = 'pcov.enabled=1'; + } else { + $settings[] = 'pcov.enabled=0'; + } + } + + if (extension_loaded('xdebug')) { + if ($collectCoverage) { + $settings[] = 'xdebug.mode=coverage'; + } + } + + return $settings; + } + + private function triggerRunnerWarningOnPhpErrors(string $section, string $output): void + { + if (str_contains($output, 'Parse error:')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s section triggered a parse error: %s', + $section, + $output, + ), + ); + } + + if (str_contains($output, 'Fatal error:')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s section triggered a fatal error: %s', + $section, + $output, + ), + ); + } + } +} diff --git a/src/Runner/Phpt/templates/phpt.tpl b/src/Runner/Phpt/templates/phpt.tpl new file mode 100644 index 00000000000..c42518886b5 --- /dev/null +++ b/src/Runner/Phpt/templates/phpt.tpl @@ -0,0 +1,56 @@ +{driverMethod}($filter), + $filter + ); + + if ({codeCoverageCacheDirectory}) { + $coverage->cacheStaticAnalysis({codeCoverageCacheDirectory}); + } + + $coverage->start(__FILE__); +} + +register_shutdown_function( + function() use ($coverage) { + $output = null; + + if ($coverage) { + $output = $coverage->stop(); + } + + file_put_contents('{coverageFile}', serialize($output)); + } +); + +ob_end_clean(); + +require '{job}'; diff --git a/src/Runner/ResultCache/DefaultResultCache.php b/src/Runner/ResultCache/DefaultResultCache.php new file mode 100644 index 00000000000..0d700a9a035 --- /dev/null +++ b/src/Runner/ResultCache/DefaultResultCache.php @@ -0,0 +1,159 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use const DIRECTORY_SEPARATOR; +use const LOCK_EX; +use function array_keys; +use function assert; +use function dirname; +use function file_get_contents; +use function file_put_contents; +use function is_array; +use function is_dir; +use function is_file; +use function json_decode; +use function json_encode; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\Runner\Exception; +use PHPUnit\Util\Filesystem; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DefaultResultCache implements ResultCache +{ + private const int VERSION = 2; + private const string DEFAULT_RESULT_CACHE_FILENAME = '.phpunit.result.cache'; + private readonly string $cacheFilename; + + /** + * @var array + */ + private array $defects = []; + + /** + * @var array + */ + private array $times = []; + + public function __construct(?string $filepath = null) + { + if ($filepath !== null && is_dir($filepath)) { + $filepath .= DIRECTORY_SEPARATOR . self::DEFAULT_RESULT_CACHE_FILENAME; + } + + $this->cacheFilename = $filepath ?? $_ENV['PHPUNIT_RESULT_CACHE'] ?? self::DEFAULT_RESULT_CACHE_FILENAME; + } + + public function setStatus(ResultCacheId $id, TestStatus $status): void + { + if ($status->isSuccess()) { + return; + } + + $this->defects[$id->asString()] = $status; + } + + public function status(ResultCacheId $id): TestStatus + { + return $this->defects[$id->asString()] ?? TestStatus::unknown(); + } + + public function setTime(ResultCacheId $id, float $time): void + { + $this->times[$id->asString()] = $time; + } + + public function time(ResultCacheId $id): float + { + return $this->times[$id->asString()] ?? 0.0; + } + + public function mergeWith(self $other): void + { + foreach ($other->defects as $id => $defect) { + $this->defects[$id] = $defect; + } + + foreach ($other->times as $id => $time) { + $this->times[$id] = $time; + } + } + + public function load(): void + { + if (!is_file($this->cacheFilename)) { + return; + } + + $contents = file_get_contents($this->cacheFilename); + + if ($contents === false) { + return; + } + + $data = json_decode( + $contents, + true, + ); + + if ($data === null) { + return; + } + + if (!isset($data['version'])) { + return; + } + + if ($data['version'] !== self::VERSION) { + return; + } + + assert(isset($data['defects']) && is_array($data['defects'])); + assert(isset($data['times']) && is_array($data['times'])); + + foreach (array_keys($data['defects']) as $test) { + $data['defects'][$test] = TestStatus::from($data['defects'][$test]); + } + + $this->defects = $data['defects']; + $this->times = $data['times']; + } + + /** + * @throws Exception + */ + public function persist(): void + { + if (!Filesystem::createDirectory(dirname($this->cacheFilename))) { + throw new DirectoryDoesNotExistException(dirname($this->cacheFilename)); + } + + $data = [ + 'version' => self::VERSION, + 'defects' => [], + 'times' => $this->times, + ]; + + foreach ($this->defects as $test => $status) { + $data['defects'][$test] = $status->asInt(); + } + + file_put_contents( + $this->cacheFilename, + json_encode($data), + LOCK_EX, + ); + } +} diff --git a/src/Runner/ResultCache/NullResultCache.php b/src/Runner/ResultCache/NullResultCache.php new file mode 100644 index 00000000000..46417d40ae9 --- /dev/null +++ b/src/Runner/ResultCache/NullResultCache.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Framework\TestStatus\TestStatus; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NullResultCache implements ResultCache +{ + public function setStatus(ResultCacheId $id, TestStatus $status): void + { + } + + public function status(ResultCacheId $id): TestStatus + { + return TestStatus::unknown(); + } + + public function setTime(ResultCacheId $id, float $time): void + { + } + + public function time(ResultCacheId $id): float + { + return 0; + } + + public function load(): void + { + } + + public function persist(): void + { + } +} diff --git a/src/Runner/ResultCache/ResultCache.php b/src/Runner/ResultCache/ResultCache.php new file mode 100644 index 00000000000..a3d62f50b3c --- /dev/null +++ b/src/Runner/ResultCache/ResultCache.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Framework\TestStatus\TestStatus; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface ResultCache +{ + public function setStatus(ResultCacheId $id, TestStatus $status): void; + + public function status(ResultCacheId $id): TestStatus; + + public function setTime(ResultCacheId $id, float $time): void; + + public function time(ResultCacheId $id): float; + + public function load(): void; + + public function persist(): void; +} diff --git a/src/Runner/ResultCache/ResultCacheHandler.php b/src/Runner/ResultCache/ResultCacheHandler.php new file mode 100644 index 00000000000..b0b45c6d5e9 --- /dev/null +++ b/src/Runner/ResultCache/ResultCacheHandler.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use function round; +use PHPUnit\Event\Event; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Framework\InvalidArgumentException; +use PHPUnit\Framework\TestStatus\TestStatus; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ResultCacheHandler +{ + private readonly ResultCache $cache; + private ?HRTime $time = null; + private int $testSuite = 0; + + public function __construct(ResultCache $cache, Facade $facade) + { + $this->cache = $cache; + + $this->registerSubscribers($facade); + } + + public function testSuiteStarted(): void + { + $this->testSuite++; + } + + public function testSuiteFinished(): void + { + $this->testSuite--; + + if ($this->testSuite === 0) { + $this->cache->persist(); + } + } + + public function testPrepared(Prepared $event): void + { + $this->time = $event->telemetryInfo()->time(); + } + + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->cache->setStatus( + ResultCacheId::fromTest($event->test()), + TestStatus::incomplete($event->throwable()->message()), + ); + } + + public function testConsideredRisky(ConsideredRisky $event): void + { + $this->cache->setStatus( + ResultCacheId::fromTest($event->test()), + TestStatus::risky($event->message()), + ); + } + + public function testErrored(Errored $event): void + { + $this->cache->setStatus( + ResultCacheId::fromTest($event->test()), + TestStatus::error($event->throwable()->message()), + ); + } + + public function testFailed(Failed $event): void + { + $this->cache->setStatus( + ResultCacheId::fromTest($event->test()), + TestStatus::failure($event->throwable()->message()), + ); + } + + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function testSkipped(Skipped $event): void + { + $this->cache->setStatus( + ResultCacheId::fromTest($event->test()), + TestStatus::skipped($event->message()), + ); + + $this->cache->setTime(ResultCacheId::fromTest($event->test()), $this->duration($event)); + } + + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function testFinished(Finished $event): void + { + $this->cache->setTime(ResultCacheId::fromTest($event->test()), $this->duration($event)); + + $this->time = null; + } + + /** + * @throws \PHPUnit\Event\InvalidArgumentException + * @throws InvalidArgumentException + */ + private function duration(Event $event): float + { + if ($this->time === null) { + return 0.0; + } + + return round($event->telemetryInfo()->time()->duration($this->time)->asFloat(), 3); + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new TestSuiteStartedSubscriber($this), + new TestSuiteFinishedSubscriber($this), + new TestPreparedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestConsideredRiskySubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestSkippedSubscriber($this), + new TestFinishedSubscriber($this), + ); + } +} diff --git a/src/Runner/ResultCache/ResultCacheId.php b/src/Runner/ResultCache/ResultCacheId.php new file mode 100644 index 00000000000..35a84f287e7 --- /dev/null +++ b/src/Runner/ResultCache/ResultCacheId.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\TestCase; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ResultCacheId +{ + public static function fromTest(Test $test): self + { + if ($test instanceof TestMethod) { + return new self($test->className() . '::' . $test->name()); + } + + return new self($test->id()); + } + + public static function fromReorderable(Reorderable $reorderable): self + { + return new self($reorderable->sortId()); + } + + /** + * For use in PHPUnit tests only! + * + * @param class-string $class + */ + public static function fromTestClassAndMethodName(string $class, string $methodName): self + { + return new self($class . '::' . $methodName); + } + + private function __construct( + private string $id, + ) { + } + + public function asString(): string + { + return $this->id; + } +} diff --git a/src/Runner/ResultCache/Subscriber/Subscriber.php b/src/Runner/ResultCache/Subscriber/Subscriber.php new file mode 100644 index 00000000000..d64dd9f4a22 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private ResultCacheHandler $handler; + + public function __construct(ResultCacheHandler $handler) + { + $this->handler = $handler; + } + + protected function handler(): ResultCacheHandler + { + return $this->handler; + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.php b/src/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.php new file mode 100644 index 00000000000..b2d934013ab --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestConsideredRiskySubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->handler()->testConsideredRisky($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestErroredSubscriber.php b/src/Runner/ResultCache/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..ff34e0d8f33 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->handler()->testErrored($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestFailedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..082fa51bd6a --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->handler()->testFailed($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestFinishedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..65f75fcb6f5 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Finished $event): void + { + $this->handler()->testFinished($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php b/src/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..d9c65cf8cff --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->handler()->testMarkedIncomplete($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..a92b82777f0 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->handler()->testPrepared($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestSkippedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..0e493bdc25b --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\InvalidArgumentException; +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + /** + * @throws \PHPUnit\Framework\InvalidArgumentException + * @throws InvalidArgumentException + */ + public function notify(Skipped $event): void + { + $this->handler()->testSkipped($event); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php new file mode 100644 index 00000000000..1ef0cc3fb46 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestSuiteFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->handler()->testSuiteFinished(); + } +} diff --git a/src/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php b/src/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php new file mode 100644 index 00000000000..cddedf511d6 --- /dev/null +++ b/src/Runner/ResultCache/Subscriber/TestSuiteStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->handler()->testSuiteStarted(); + } +} diff --git a/src/Runner/ShutdownHandler.php b/src/Runner/ShutdownHandler.php new file mode 100644 index 00000000000..129ec9f868f --- /dev/null +++ b/src/Runner/ShutdownHandler.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use const PHP_EOL; +use function getmypid; +use function register_shutdown_function; +use function rtrim; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ShutdownHandler +{ + private static bool $registered = false; + private static string $message = ''; + + public static function setMessage(string $message): void + { + self::register(); + + self::$message = $message; + } + + public static function resetMessage(): void + { + self::$message = ''; + } + + private static function register(): void + { + if (self::$registered) { + return; + } + + self::$registered = true; + $pid = getmypid(); + + register_shutdown_function( + static function () use ($pid): void + { + $message = rtrim(self::$message); + + if ($message === '' || $pid !== getmypid()) { + return; + } + + print $message . PHP_EOL; + }, + ); + } +} diff --git a/src/Runner/TestResult/Collector.php b/src/Runner/TestResult/Collector.php new file mode 100644 index 00000000000..5615a0dade7 --- /dev/null +++ b/src/Runner/TestResult/Collector.php @@ -0,0 +1,681 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_values; +use function assert; +use function count; +use function implode; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\Skipped as TestSkipped; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\TestRunner\ChildProcessErrored; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\TestSuiteForTestClass; +use PHPUnit\Event\TestSuite\TestSuiteForTestMethodWithDataProvider; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TestRunner\TestResult\Issues\Issue; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Collector +{ + private readonly IssueFilter $issueFilter; + private int $numberOfTests = 0; + private int $numberOfTestsRun = 0; + private int $numberOfAssertions = 0; + private bool $prepared = false; + private bool $childProcessErrored = false; + + /** + * @var non-negative-int + */ + private int $numberOfIssuesIgnoredByBaseline = 0; + + /** + * @var list + */ + private array $testErroredEvents = []; + + /** + * @var list + */ + private array $testFailedEvents = []; + + /** + * @var list + */ + private array $testMarkedIncompleteEvents = []; + + /** + * @var list + */ + private array $testSuiteSkippedEvents = []; + + /** + * @var list + */ + private array $testSkippedEvents = []; + + /** + * @var array> + */ + private array $testConsideredRiskyEvents = []; + + /** + * @var array> + */ + private array $testTriggeredPhpunitDeprecationEvents = []; + + /** + * @var array> + */ + private array $testTriggeredPhpunitErrorEvents = []; + + /** + * @var array> + */ + private array $testTriggeredPhpunitNoticeEvents = []; + + /** + * @var array> + */ + private array $testTriggeredPhpunitWarningEvents = []; + + /** + * @var list + */ + private array $testRunnerTriggeredDeprecationEvents = []; + + /** + * @var list + */ + private array $testRunnerTriggeredNoticeEvents = []; + + /** + * @var list + */ + private array $testRunnerTriggeredWarningEvents = []; + + /** + * @var array + */ + private array $errors = []; + + /** + * @var array + */ + private array $deprecations = []; + + /** + * @var array + */ + private array $notices = []; + + /** + * @var array + */ + private array $warnings = []; + + /** + * @var array + */ + private array $phpDeprecations = []; + + /** + * @var array + */ + private array $phpNotices = []; + + /** + * @var array + */ + private array $phpWarnings = []; + + public function __construct(Facade $facade, IssueFilter $issueFilter) + { + $facade->registerSubscribers( + new ExecutionStartedSubscriber($this), + new TestSuiteSkippedSubscriber($this), + new TestSuiteStartedSubscriber($this), + new TestSuiteFinishedSubscriber($this), + new TestPreparedSubscriber($this), + new TestFinishedSubscriber($this), + new BeforeTestClassMethodErroredSubscriber($this), + new BeforeTestClassMethodFailedSubscriber($this), + new AfterTestClassMethodErroredSubscriber($this), + new AfterTestClassMethodFailedSubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestSkippedSubscriber($this), + new TestConsideredRiskySubscriber($this), + new TestTriggeredDeprecationSubscriber($this), + new TestTriggeredErrorSubscriber($this), + new TestTriggeredNoticeSubscriber($this), + new TestTriggeredPhpDeprecationSubscriber($this), + new TestTriggeredPhpNoticeSubscriber($this), + new TestTriggeredPhpunitDeprecationSubscriber($this), + new TestTriggeredPhpunitErrorSubscriber($this), + new TestTriggeredPhpunitNoticeSubscriber($this), + new TestTriggeredPhpunitWarningSubscriber($this), + new TestTriggeredPhpWarningSubscriber($this), + new TestTriggeredWarningSubscriber($this), + new TestRunnerTriggeredDeprecationSubscriber($this), + new TestRunnerTriggeredNoticeSubscriber($this), + new TestRunnerTriggeredWarningSubscriber($this), + new ChildProcessErroredSubscriber($this), + ); + + $this->issueFilter = $issueFilter; + } + + public function result(): TestResult + { + return new TestResult( + $this->numberOfTests, + $this->numberOfTestsRun, + $this->numberOfAssertions, + $this->testErroredEvents, + $this->testFailedEvents, + $this->testConsideredRiskyEvents, + $this->testSuiteSkippedEvents, + $this->testSkippedEvents, + $this->testMarkedIncompleteEvents, + $this->testTriggeredPhpunitDeprecationEvents, + $this->testTriggeredPhpunitErrorEvents, + $this->testTriggeredPhpunitNoticeEvents, + $this->testTriggeredPhpunitWarningEvents, + $this->testRunnerTriggeredDeprecationEvents, + $this->testRunnerTriggeredNoticeEvents, + $this->testRunnerTriggeredWarningEvents, + array_values($this->errors), + array_values($this->deprecations), + array_values($this->notices), + array_values($this->warnings), + array_values($this->phpDeprecations), + array_values($this->phpNotices), + array_values($this->phpWarnings), + $this->numberOfIssuesIgnoredByBaseline, + ); + } + + public function executionStarted(ExecutionStarted $event): void + { + $this->numberOfTests = $event->testSuite()->count(); + } + + public function testSuiteSkipped(TestSuiteSkipped $event): void + { + $testSuite = $event->testSuite(); + + if (!$testSuite->isForTestClass()) { + return; + } + + $this->testSuiteSkippedEvents[] = $event; + } + + public function testSuiteStarted(TestSuiteStarted $event): void + { + $testSuite = $event->testSuite(); + + if (!$testSuite->isForTestClass()) { + return; + } + } + + public function testSuiteFinished(TestSuiteFinished $event): void + { + $testSuite = $event->testSuite(); + + if ($testSuite->isWithName()) { + return; + } + + if ($testSuite->isForTestMethodWithDataProvider()) { + assert($testSuite instanceof TestSuiteForTestMethodWithDataProvider); + assert(count($testSuite->tests()->asArray()) > 0); + + $test = $testSuite->tests()->asArray()[0]; + + assert($test instanceof TestMethod); + + foreach ($this->testFailedEvents as $testFailedEvent) { + if ($testFailedEvent->test()->isTestMethod() && $testFailedEvent->test()->methodName() === $test->methodName()) { + return; + } + } + + PassedTests::instance()->testMethodPassed($test, null); + + return; + } + + assert($testSuite instanceof TestSuiteForTestClass); + + PassedTests::instance()->testClassPassed($testSuite->className()); + } + + public function testPrepared(): void + { + $this->prepared = true; + } + + public function testFinished(Finished $event): void + { + $this->numberOfAssertions += $event->numberOfAssertionsPerformed(); + + $this->numberOfTestsRun++; + + $this->prepared = false; + $this->childProcessErrored = false; + } + + public function beforeTestClassMethodErrored(BeforeFirstTestMethodErrored $event): void + { + $this->testErroredEvents[] = $event; + + $this->numberOfTestsRun++; + } + + public function beforeTestClassMethodFailed(BeforeFirstTestMethodFailed $event): void + { + $this->testFailedEvents[] = $event; + + $this->numberOfTestsRun++; + } + + public function afterTestClassMethodErrored(AfterLastTestMethodErrored $event): void + { + $this->testErroredEvents[] = $event; + } + + public function afterTestClassMethodFailed(AfterLastTestMethodFailed $event): void + { + $this->testFailedEvents[] = $event; + } + + public function testErrored(Errored $event): void + { + $this->testErroredEvents[] = $event; + + if ($this->childProcessErrored) { + return; + } + + if (!$this->prepared) { + $this->numberOfTestsRun++; + } + } + + public function testFailed(Failed $event): void + { + $this->testFailedEvents[] = $event; + } + + public function testMarkedIncomplete(MarkedIncomplete $event): void + { + $this->testMarkedIncompleteEvents[] = $event; + } + + public function testSkipped(TestSkipped $event): void + { + $this->testSkippedEvents[] = $event; + + if (!$this->prepared) { + $this->numberOfTestsRun++; + } + } + + public function testConsideredRisky(ConsideredRisky $event): void + { + if (!isset($this->testConsideredRiskyEvents[$event->test()->id()])) { + $this->testConsideredRiskyEvents[$event->test()->id()] = []; + } + + $this->testConsideredRiskyEvents[$event->test()->id()][] = $event; + } + + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->deprecations[$id])) { + $this->deprecations[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + $event->stackTrace(), + ); + + return; + } + + $this->deprecations[$id]->triggeredBy($event->test()); + } + + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->phpDeprecations[$id])) { + $this->phpDeprecations[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->phpDeprecations[$id]->triggeredBy($event->test()); + } + + public function testTriggeredPhpunitDeprecation(PhpunitDeprecationTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()] = []; + } + + $this->testTriggeredPhpunitDeprecationEvents[$event->test()->id()][] = $event; + } + + public function testTriggeredPhpunitNotice(PhpunitNoticeTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitNoticeEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitNoticeEvents[$event->test()->id()] = []; + } + + $this->testTriggeredPhpunitNoticeEvents[$event->test()->id()][] = $event; + } + + public function testTriggeredError(ErrorTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + $id = $this->issueId($event); + + if (!isset($this->errors[$id])) { + $this->errors[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->errors[$id]->triggeredBy($event->test()); + } + + public function testTriggeredNotice(NoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->notices[$id])) { + $this->notices[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->notices[$id]->triggeredBy($event->test()); + } + + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->phpNotices[$id])) { + $this->phpNotices[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->phpNotices[$id]->triggeredBy($event->test()); + } + + public function testTriggeredWarning(WarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->warnings[$id])) { + $this->warnings[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->warnings[$id]->triggeredBy($event->test()); + } + + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if (!$this->issueFilter->shouldBeProcessed($event)) { + return; + } + + if ($event->ignoredByBaseline()) { + $this->numberOfIssuesIgnoredByBaseline++; + + return; + } + + $id = $this->issueId($event); + + if (!isset($this->phpWarnings[$id])) { + $this->phpWarnings[$id] = Issue::from( + $event->file(), + $event->line(), + $event->message(), + $event->test(), + ); + + return; + } + + $this->phpWarnings[$id]->triggeredBy($event->test()); + } + + public function testTriggeredPhpunitError(PhpunitErrorTriggered $event): void + { + if (!isset($this->testTriggeredPhpunitErrorEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitErrorEvents[$event->test()->id()] = []; + } + + $this->testTriggeredPhpunitErrorEvents[$event->test()->id()][] = $event; + } + + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if ($event->ignoredByTest()) { + return; + } + + if (!isset($this->testTriggeredPhpunitWarningEvents[$event->test()->id()])) { + $this->testTriggeredPhpunitWarningEvents[$event->test()->id()] = []; + } + + $this->testTriggeredPhpunitWarningEvents[$event->test()->id()][] = $event; + } + + public function testRunnerTriggeredDeprecation(TestRunnerDeprecationTriggered $event): void + { + $this->testRunnerTriggeredDeprecationEvents[] = $event; + } + + public function testRunnerTriggeredNotice(TestRunnerNoticeTriggered $event): void + { + $this->testRunnerTriggeredNoticeEvents[] = $event; + } + + public function testRunnerTriggeredWarning(TestRunnerWarningTriggered $event): void + { + $this->testRunnerTriggeredWarningEvents[] = $event; + } + + public function childProcessErrored(ChildProcessErrored $event): void + { + $this->childProcessErrored = true; + } + + public function hasErroredTests(): bool + { + return $this->testErroredEvents !== []; + } + + public function hasFailedTests(): bool + { + return $this->testFailedEvents !== []; + } + + public function hasRiskyTests(): bool + { + return $this->testConsideredRiskyEvents !== []; + } + + public function hasSkippedTests(): bool + { + return $this->testSkippedEvents !== []; + } + + public function hasIncompleteTests(): bool + { + return $this->testMarkedIncompleteEvents !== []; + } + + public function hasDeprecations(): bool + { + return $this->deprecations !== [] || + $this->phpDeprecations !== [] || + $this->testTriggeredPhpunitDeprecationEvents !== [] || + $this->testRunnerTriggeredDeprecationEvents !== []; + } + + public function hasNotices(): bool + { + return $this->notices !== [] || + $this->phpNotices !== []; + } + + public function hasWarnings(): bool + { + return $this->warnings !== [] || + $this->phpWarnings !== [] || + $this->testTriggeredPhpunitWarningEvents !== [] || + $this->testRunnerTriggeredWarningEvents !== []; + } + + /** + * @return non-empty-string + */ + private function issueId(DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpWarningTriggered|WarningTriggered $event): string + { + return implode(':', [$event->file(), $event->line(), $event->message()]); + } +} diff --git a/src/Runner/TestResult/Facade.php b/src/Runner/TestResult/Facade.php new file mode 100644 index 00000000000..c95ff53b0fb --- /dev/null +++ b/src/Runner/TestResult/Facade.php @@ -0,0 +1,113 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_any; +use function str_contains; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollectorFacade; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?Collector $collector = null; + + public static function init(): void + { + self::collector(); + } + + public static function result(): TestResult + { + return self::collector()->result(); + } + + public static function shouldStop(): bool + { + $configuration = ConfigurationRegistry::get(); + $collector = self::collector(); + + if (($configuration->stopOnDefect() || $configuration->stopOnError()) && $collector->hasErroredTests()) { + return true; + } + + if (($configuration->stopOnDefect() || $configuration->stopOnFailure()) && $collector->hasFailedTests()) { + return true; + } + + if (($configuration->stopOnDefect() || $configuration->stopOnWarning()) && $collector->hasWarnings()) { + return true; + } + + if (($configuration->stopOnDefect() || $configuration->stopOnRisky()) && $collector->hasRiskyTests()) { + return true; + } + + if (self::stopOnDeprecation($configuration)) { + return true; + } + + if ($configuration->stopOnNotice() && $collector->hasNotices()) { + return true; + } + + if ($configuration->stopOnIncomplete() && $collector->hasIncompleteTests()) { + return true; + } + + if ($configuration->stopOnSkipped() && $collector->hasSkippedTests()) { + return true; + } + + return false; + } + + private static function collector(): Collector + { + if (self::$collector === null) { + $configuration = ConfigurationRegistry::get(); + + self::$collector = new Collector( + EventFacade::instance(), + new IssueFilter($configuration->source()), + ); + } + + return self::$collector; + } + + private static function stopOnDeprecation(Configuration $configuration): bool + { + if (!$configuration->stopOnDeprecation()) { + return false; + } + + $deprecations = DeprecationCollectorFacade::filteredDeprecations(); + + if (!$configuration->hasSpecificDeprecationToStopOn()) { + return $deprecations !== []; + } + + return array_any( + $deprecations, + static fn (string $deprecation) => str_contains( + $deprecation, + $configuration->specificDeprecationToStopOn(), + ), + ); + } +} diff --git a/src/Runner/TestResult/Issue.php b/src/Runner/TestResult/Issue.php new file mode 100644 index 00000000000..12ade5c3f5d --- /dev/null +++ b/src/Runner/TestResult/Issue.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult\Issues; + +use function array_keys; +use function count; +use PHPUnit\Event\Code\Test; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Issue +{ + /** + * @var non-empty-string + */ + private readonly string $file; + + /** + * @var positive-int + */ + private readonly int $line; + + /** + * @var non-empty-string + */ + private readonly string $description; + + /** + * @var non-empty-array + */ + private array $triggeringTests; + + /** + * @var ?non-empty-string + */ + private ?string $stackTrace; + + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + public static function from(string $file, int $line, string $description, Test $triggeringTest, ?string $stackTrace = null): self + { + return new self($file, $line, $description, $triggeringTest, $stackTrace); + } + + /** + * @param non-empty-string $file + * @param positive-int $line + * @param non-empty-string $description + */ + private function __construct(string $file, int $line, string $description, Test $triggeringTest, ?string $stackTrace) + { + $this->file = $file; + $this->line = $line; + $this->description = $description; + $this->stackTrace = $stackTrace; + + $this->triggeringTests = [ + $triggeringTest->id() => [ + 'test' => $triggeringTest, + 'count' => 1, + ], + ]; + } + + public function triggeredBy(Test $test): void + { + if (isset($this->triggeringTests[$test->id()])) { + $this->triggeringTests[$test->id()]['count']++; + + return; + } + + $this->triggeringTests[$test->id()] = [ + 'test' => $test, + 'count' => 1, + ]; + } + + /** + * @return non-empty-string + */ + public function file(): string + { + return $this->file; + } + + /** + * @return positive-int + */ + public function line(): int + { + return $this->line; + } + + /** + * @return non-empty-string + */ + public function description(): string + { + return $this->description; + } + + /** + * @return non-empty-array + */ + public function triggeringTests(): array + { + return $this->triggeringTests; + } + + /** + * @phpstan-assert-if-true !null $this->stackTrace + */ + public function hasStackTrace(): bool + { + return $this->stackTrace !== null; + } + + /** + * @return ?non-empty-string + */ + public function stackTrace(): ?string + { + return $this->stackTrace; + } + + public function triggeredInTest(): bool + { + return count($this->triggeringTests) === 1 && + $this->file === $this->triggeringTests[array_keys($this->triggeringTests)[0]]['test']->file(); + } +} diff --git a/src/Runner/TestResult/PassedTests.php b/src/Runner/TestResult/PassedTests.php new file mode 100644 index 00000000000..2f611461d6f --- /dev/null +++ b/src/Runner/TestResult/PassedTests.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function array_merge; +use function assert; +use function explode; +use function in_array; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Framework\TestSize\Known; +use PHPUnit\Framework\TestSize\TestSize; +use PHPUnit\Metadata\Api\Groups; +use ReflectionMethod; +use ReflectionNamedType; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PassedTests +{ + private static ?self $instance = null; + + /** + * @var list + */ + private array $passedTestClasses = []; + + /** + * @var array + */ + private array $passedTestMethods = []; + + public static function instance(): self + { + if (self::$instance !== null) { + return self::$instance; + } + + self::$instance = new self; + + return self::$instance; + } + + /** + * @param class-string $className + */ + public function testClassPassed(string $className): void + { + $this->passedTestClasses[] = $className; + } + + public function testMethodPassed(TestMethod $test, mixed $returnValue): void + { + $size = (new Groups)->size( + $test->className(), + $test->methodName(), + ); + + $this->passedTestMethods[$test->className() . '::' . $test->methodName()] = [ + 'returnValue' => $returnValue, + 'size' => $size, + ]; + } + + public function import(self $other): void + { + $this->passedTestClasses = array_merge( + $this->passedTestClasses, + $other->passedTestClasses, + ); + + $this->passedTestMethods = array_merge( + $this->passedTestMethods, + $other->passedTestMethods, + ); + } + + /** + * @param class-string $className + */ + public function hasTestClassPassed(string $className): bool + { + return in_array($className, $this->passedTestClasses, true); + } + + public function hasTestMethodPassed(string $method): bool + { + return isset($this->passedTestMethods[$method]); + } + + public function isGreaterThan(string $method, TestSize $other): bool + { + if ($other->isUnknown()) { + return false; + } + + assert($other instanceof Known); + + $size = $this->passedTestMethods[$method]['size']; + + if ($size->isUnknown()) { + return false; + } + + assert($size instanceof Known); + + return $size->isGreaterThan($other); + } + + public function hasReturnValue(string $method): bool + { + $returnType = new ReflectionMethod(...explode('::', $method))->getReturnType(); + + return !$returnType instanceof ReflectionNamedType || !in_array($returnType->getName(), ['never', 'void'], true); + } + + public function returnValue(string $method): mixed + { + if (isset($this->passedTestMethods[$method])) { + return $this->passedTestMethods[$method]['returnValue']; + } + + return null; + } +} diff --git a/src/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php b/src/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php new file mode 100644 index 00000000000..eb94433bdeb --- /dev/null +++ b/src/Runner/TestResult/Subscriber/AfterTestClassMethodErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestClassMethodErroredSubscriber extends Subscriber implements AfterLastTestMethodErroredSubscriber +{ + public function notify(AfterLastTestMethodErrored $event): void + { + $this->collector()->afterTestClassMethodErrored($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php b/src/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php new file mode 100644 index 00000000000..e207ba1d079 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/AfterTestClassMethodFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\AfterLastTestMethodFailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AfterTestClassMethodFailedSubscriber extends Subscriber implements AfterLastTestMethodFailedSubscriber +{ + public function notify(AfterLastTestMethodFailed $event): void + { + $this->collector()->afterTestClassMethodFailed($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php b/src/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php new file mode 100644 index 00000000000..1929125e573 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/BeforeTestClassMethodErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodErroredSubscriber extends Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->collector()->beforeTestClassMethodErrored($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.php b/src/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.php new file mode 100644 index 00000000000..0e69855a0ae --- /dev/null +++ b/src/Runner/TestResult/Subscriber/BeforeTestClassMethodFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodFailedSubscriber extends Subscriber implements BeforeFirstTestMethodFailedSubscriber +{ + public function notify(BeforeFirstTestMethodFailed $event): void + { + $this->collector()->beforeTestClassMethodFailed($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.php b/src/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.php new file mode 100644 index 00000000000..3d70d88ede8 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/ChildProcessErroredSubscriber.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\ChildProcessErrored; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErroredSubscriber extends Subscriber implements \PHPUnit\Event\TestRunner\ChildProcessErroredSubscriber +{ + public function notify(ChildProcessErrored $event): void + { + $this->collector()->childProcessErrored($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php b/src/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php new file mode 100644 index 00000000000..b54ae9e724a --- /dev/null +++ b/src/Runner/TestResult/Subscriber/ExecutionStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber as TestRunnerExecutionStartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ExecutionStartedSubscriber extends Subscriber implements TestRunnerExecutionStartedSubscriber +{ + public function notify(ExecutionStarted $event): void + { + $this->collector()->executionStarted($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/Subscriber.php b/src/Runner/TestResult/Subscriber/Subscriber.php new file mode 100644 index 00000000000..36be4941b31 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private Collector $collector; + + public function __construct(Collector $collector) + { + $this->collector = $collector; + } + + protected function collector(): Collector + { + return $this->collector; + } +} diff --git a/src/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php b/src/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php new file mode 100644 index 00000000000..8584fddcc27 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestConsideredRiskySubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->collector()->testConsideredRisky($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestErroredSubscriber.php b/src/Runner/TestResult/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..a97c21a689e --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->collector()->testErrored($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestFailedSubscriber.php b/src/Runner/TestResult/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..118b304cdc6 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->collector()->testFailed($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestFinishedSubscriber.php b/src/Runner/TestResult/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..37fe67d0f47 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->collector()->testFinished($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php b/src/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..c9d13ab5620 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->collector()->testMarkedIncomplete($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestPreparedSubscriber.php b/src/Runner/TestResult/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..6dd05ca75ec --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->collector()->testPrepared(); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..36b3ea03917 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\DeprecationTriggered; +use PHPUnit\Event\TestRunner\DeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testRunnerTriggeredDeprecation($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.php b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.php new file mode 100644 index 00000000000..8fd9bc4b86e --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\NoticeTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testRunnerTriggeredNotice($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php new file mode 100644 index 00000000000..cc01d5db8c1 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestRunnerTriggeredWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestRunner\WarningTriggered; +use PHPUnit\Event\TestRunner\WarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testRunnerTriggeredWarning($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestSkippedSubscriber.php b/src/Runner/TestResult/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..152db85bf77 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSkipped($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.php b/src/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.php new file mode 100644 index 00000000000..e5f2acac512 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestSuiteFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Finished; +use PHPUnit\Event\TestSuite\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->collector()->testSuiteFinished($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php b/src/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php new file mode 100644 index 00000000000..0c7cd7abb8d --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestSuiteSkippedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Skipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->collector()->testSuiteSkipped($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php b/src/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php new file mode 100644 index 00000000000..d3cb3bffdd0 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestSuiteStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\TestSuite\Started; +use PHPUnit\Event\TestSuite\StartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteStartedSubscriber extends Subscriber implements StartedSubscriber +{ + public function notify(Started $event): void + { + $this->collector()->testSuiteStarted($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..81e93eb3472 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->collector()->testTriggeredDeprecation($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.php new file mode 100644 index 00000000000..0aef461dbcb --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredErrorSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\ErrorTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredErrorSubscriber extends Subscriber implements ErrorTriggeredSubscriber +{ + public function notify(ErrorTriggered $event): void + { + $this->collector()->testTriggeredError($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php new file mode 100644 index 00000000000..67b73c06a01 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->collector()->testTriggeredNotice($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php new file mode 100644 index 00000000000..5cd17e3f981 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpDeprecation($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php new file mode 100644 index 00000000000..9af0d3206fb --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpNotice($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php new file mode 100644 index 00000000000..18eaf4f17a6 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpWarning($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php new file mode 100644 index 00000000000..3475f11aae1 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->collector()->testTriggeredPhpunitDeprecation($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php new file mode 100644 index 00000000000..0ceba9caa29 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitErrorSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitErrorSubscriber extends Subscriber implements PhpunitErrorTriggeredSubscriber +{ + public function notify(PhpunitErrorTriggered $event): void + { + $this->collector()->testTriggeredPhpunitError($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php new file mode 100644 index 00000000000..f7ebfd1463e --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitNoticeSubscriber extends Subscriber implements PhpunitNoticeTriggeredSubscriber +{ + public function notify(PhpunitNoticeTriggered $event): void + { + $this->collector()->testTriggeredPhpunitNotice($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php new file mode 100644 index 00000000000..376c4b60e80 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredPhpunitWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->collector()->testTriggeredPhpunitWarning($event); + } +} diff --git a/src/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.php b/src/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.php new file mode 100644 index 00000000000..d5fe3ed5cd5 --- /dev/null +++ b/src/Runner/TestResult/Subscriber/TestTriggeredWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->collector()->testTriggeredWarning($event); + } +} diff --git a/src/Runner/TestResult/TestResult.php b/src/Runner/TestResult/TestResult.php new file mode 100644 index 00000000000..f491718f787 --- /dev/null +++ b/src/Runner/TestResult/TestResult.php @@ -0,0 +1,647 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestRunner\TestResult; + +use function count; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\AfterLastTestMethodFailed; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodFailed; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\Skipped as TestSkipped; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\TestRunner\TestResult\Issues\Issue; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestResult +{ + private int $numberOfTests; + private int $numberOfTestsRun; + private int $numberOfAssertions; + + /** + * @var list + */ + private array $testErroredEvents; + + /** + * @var list + */ + private array $testFailedEvents; + + /** + * @var list + */ + private array $testMarkedIncompleteEvents; + + /** + * @var list + */ + private array $testSuiteSkippedEvents; + + /** + * @var list + */ + private array $testSkippedEvents; + + /** + * @var array> + */ + private array $testConsideredRiskyEvents; + + /** + * @var array> + */ + private array $testTriggeredPhpunitDeprecationEvents; + + /** + * @var array> + */ + private array $testTriggeredPhpunitErrorEvents; + + /** + * @var array> + */ + private array $testTriggeredPhpunitNoticeEvents; + + /** + * @var array> + */ + private array $testTriggeredPhpunitWarningEvents; + + /** + * @var list + */ + private array $testRunnerTriggeredDeprecationEvents; + + /** + * @var list + */ + private array $testRunnerTriggeredNoticeEvents; + + /** + * @var list + */ + private array $testRunnerTriggeredWarningEvents; + + /** + * @var list + */ + private array $errors; + + /** + * @var list + */ + private array $deprecations; + + /** + * @var list + */ + private array $notices; + + /** + * @var list + */ + private array $warnings; + + /** + * @var list + */ + private array $phpDeprecations; + + /** + * @var list + */ + private array $phpNotices; + + /** + * @var list + */ + private array $phpWarnings; + + /** + * @var non-negative-int + */ + private int $numberOfIssuesIgnoredByBaseline; + + /** + * @param list $testErroredEvents + * @param list $testFailedEvents + * @param array> $testConsideredRiskyEvents + * @param list $testSuiteSkippedEvents + * @param list $testSkippedEvents + * @param list $testMarkedIncompleteEvents + * @param array> $testTriggeredPhpunitDeprecationEvents + * @param array> $testTriggeredPhpunitErrorEvents + * @param array> $testTriggeredPhpunitNoticeEvents + * @param array> $testTriggeredPhpunitWarningEvents + * @param list $testRunnerTriggeredDeprecationEvents + * @param list $testRunnerTriggeredNoticeEvents + * @param list $testRunnerTriggeredWarningEvents + * @param list $errors + * @param list $deprecations + * @param list $notices + * @param list $warnings + * @param list $phpDeprecations + * @param list $phpNotices + * @param list $phpWarnings + * @param non-negative-int $numberOfIssuesIgnoredByBaseline + */ + public function __construct(int $numberOfTests, int $numberOfTestsRun, int $numberOfAssertions, array $testErroredEvents, array $testFailedEvents, array $testConsideredRiskyEvents, array $testSuiteSkippedEvents, array $testSkippedEvents, array $testMarkedIncompleteEvents, array $testTriggeredPhpunitDeprecationEvents, array $testTriggeredPhpunitErrorEvents, array $testTriggeredPhpunitNoticeEvents, array $testTriggeredPhpunitWarningEvents, array $testRunnerTriggeredDeprecationEvents, array $testRunnerTriggeredNoticeEvents, array $testRunnerTriggeredWarningEvents, array $errors, array $deprecations, array $notices, array $warnings, array $phpDeprecations, array $phpNotices, array $phpWarnings, int $numberOfIssuesIgnoredByBaseline) + { + $this->numberOfTests = $numberOfTests; + $this->numberOfTestsRun = $numberOfTestsRun; + $this->numberOfAssertions = $numberOfAssertions; + $this->testErroredEvents = $testErroredEvents; + $this->testFailedEvents = $testFailedEvents; + $this->testConsideredRiskyEvents = $testConsideredRiskyEvents; + $this->testSuiteSkippedEvents = $testSuiteSkippedEvents; + $this->testSkippedEvents = $testSkippedEvents; + $this->testMarkedIncompleteEvents = $testMarkedIncompleteEvents; + $this->testTriggeredPhpunitDeprecationEvents = $testTriggeredPhpunitDeprecationEvents; + $this->testTriggeredPhpunitErrorEvents = $testTriggeredPhpunitErrorEvents; + $this->testTriggeredPhpunitNoticeEvents = $testTriggeredPhpunitNoticeEvents; + $this->testTriggeredPhpunitWarningEvents = $testTriggeredPhpunitWarningEvents; + $this->testRunnerTriggeredDeprecationEvents = $testRunnerTriggeredDeprecationEvents; + $this->testRunnerTriggeredNoticeEvents = $testRunnerTriggeredNoticeEvents; + $this->testRunnerTriggeredWarningEvents = $testRunnerTriggeredWarningEvents; + $this->errors = $errors; + $this->deprecations = $deprecations; + $this->notices = $notices; + $this->warnings = $warnings; + $this->phpDeprecations = $phpDeprecations; + $this->phpNotices = $phpNotices; + $this->phpWarnings = $phpWarnings; + $this->numberOfIssuesIgnoredByBaseline = $numberOfIssuesIgnoredByBaseline; + } + + public function numberOfTestsRun(): int + { + return $this->numberOfTestsRun; + } + + public function numberOfAssertions(): int + { + return $this->numberOfAssertions; + } + + /** + * @return list + */ + public function testErroredEvents(): array + { + return $this->testErroredEvents; + } + + public function numberOfTestErroredEvents(): int + { + return count($this->testErroredEvents); + } + + public function hasTestErroredEvents(): bool + { + return $this->numberOfTestErroredEvents() > 0; + } + + /** + * @return list + */ + public function testFailedEvents(): array + { + return $this->testFailedEvents; + } + + public function numberOfTestFailedEvents(): int + { + return count($this->testFailedEvents); + } + + public function hasTestFailedEvents(): bool + { + return $this->numberOfTestFailedEvents() > 0; + } + + /** + * @return array> + */ + public function testConsideredRiskyEvents(): array + { + return $this->testConsideredRiskyEvents; + } + + public function numberOfTestsWithTestConsideredRiskyEvents(): int + { + return count($this->testConsideredRiskyEvents); + } + + public function hasTestConsideredRiskyEvents(): bool + { + return $this->numberOfTestsWithTestConsideredRiskyEvents() > 0; + } + + /** + * @return list + */ + public function testSuiteSkippedEvents(): array + { + return $this->testSuiteSkippedEvents; + } + + public function numberOfTestSuiteSkippedEvents(): int + { + return count($this->testSuiteSkippedEvents); + } + + public function hasTestSuiteSkippedEvents(): bool + { + return $this->numberOfTestSuiteSkippedEvents() > 0; + } + + /** + * @return list + */ + public function testSkippedEvents(): array + { + return $this->testSkippedEvents; + } + + public function numberOfTestSkippedEvents(): int + { + return count($this->testSkippedEvents); + } + + public function hasTestSkippedEvents(): bool + { + return $this->numberOfTestSkippedEvents() > 0; + } + + /** + * @return list + */ + public function testMarkedIncompleteEvents(): array + { + return $this->testMarkedIncompleteEvents; + } + + public function numberOfTestMarkedIncompleteEvents(): int + { + return count($this->testMarkedIncompleteEvents); + } + + public function hasTestMarkedIncompleteEvents(): bool + { + return $this->numberOfTestMarkedIncompleteEvents() > 0; + } + + /** + * @return array> + */ + public function testTriggeredPhpunitDeprecationEvents(): array + { + return $this->testTriggeredPhpunitDeprecationEvents; + } + + public function numberOfTestsWithTestTriggeredPhpunitDeprecationEvents(): int + { + return count($this->testTriggeredPhpunitDeprecationEvents); + } + + public function hasTestTriggeredPhpunitDeprecationEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitDeprecationEvents() > 0; + } + + /** + * @return array> + */ + public function testTriggeredPhpunitErrorEvents(): array + { + return $this->testTriggeredPhpunitErrorEvents; + } + + public function numberOfTestsWithTestTriggeredPhpunitErrorEvents(): int + { + return count($this->testTriggeredPhpunitErrorEvents); + } + + public function hasTestTriggeredPhpunitErrorEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents() > 0; + } + + /** + * @return array> + */ + public function testTriggeredPhpunitNoticeEvents(): array + { + return $this->testTriggeredPhpunitNoticeEvents; + } + + public function numberOfTestsWithTestTriggeredPhpunitNoticeEvents(): int + { + return count($this->testTriggeredPhpunitNoticeEvents); + } + + public function hasTestTriggeredPhpunitNoticeEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitNoticeEvents() > 0; + } + + /** + * @return array> + */ + public function testTriggeredPhpunitWarningEvents(): array + { + return $this->testTriggeredPhpunitWarningEvents; + } + + public function numberOfTestsWithTestTriggeredPhpunitWarningEvents(): int + { + return count($this->testTriggeredPhpunitWarningEvents); + } + + public function hasTestTriggeredPhpunitWarningEvents(): bool + { + return $this->numberOfTestsWithTestTriggeredPhpunitWarningEvents() > 0; + } + + /** + * @return list + */ + public function testRunnerTriggeredDeprecationEvents(): array + { + return $this->testRunnerTriggeredDeprecationEvents; + } + + public function numberOfTestRunnerTriggeredDeprecationEvents(): int + { + return count($this->testRunnerTriggeredDeprecationEvents); + } + + public function hasTestRunnerTriggeredDeprecationEvents(): bool + { + return $this->numberOfTestRunnerTriggeredDeprecationEvents() > 0; + } + + /** + * @return list + */ + public function testRunnerTriggeredNoticeEvents(): array + { + return $this->testRunnerTriggeredNoticeEvents; + } + + public function numberOfTestRunnerTriggeredNoticeEvents(): int + { + return count($this->testRunnerTriggeredNoticeEvents); + } + + public function hasTestRunnerTriggeredNoticeEvents(): bool + { + return $this->numberOfTestRunnerTriggeredNoticeEvents() > 0; + } + + /** + * @return list + */ + public function testRunnerTriggeredWarningEvents(): array + { + return $this->testRunnerTriggeredWarningEvents; + } + + public function numberOfTestRunnerTriggeredWarningEvents(): int + { + return count($this->testRunnerTriggeredWarningEvents); + } + + public function hasTestRunnerTriggeredWarningEvents(): bool + { + return $this->numberOfTestRunnerTriggeredWarningEvents() > 0; + } + + public function wasSuccessful(): bool + { + return !$this->hasTestErroredEvents() && + !$this->hasTestFailedEvents() && + !$this->hasTestTriggeredPhpunitErrorEvents(); + } + + public function hasIssues(): bool + { + return $this->hasTestsWithIssues() || + $this->hasTestRunnerTriggeredWarningEvents(); + } + + public function hasTestsWithIssues(): bool + { + return $this->hasRiskyTests() || + $this->hasIncompleteTests() || + $this->hasDeprecations() || + $this->errors !== [] || + $this->hasNotices() || + $this->hasWarnings() || + $this->hasPhpunitNotices() || + $this->hasPhpunitWarnings(); + } + + /** + * @return list + */ + public function errors(): array + { + return $this->errors; + } + + /** + * @return list + */ + public function deprecations(): array + { + return $this->deprecations; + } + + /** + * @return list + */ + public function notices(): array + { + return $this->notices; + } + + /** + * @return list + */ + public function warnings(): array + { + return $this->warnings; + } + + /** + * @return list + */ + public function phpDeprecations(): array + { + return $this->phpDeprecations; + } + + /** + * @return list + */ + public function phpNotices(): array + { + return $this->phpNotices; + } + + /** + * @return list + */ + public function phpWarnings(): array + { + return $this->phpWarnings; + } + + public function hasTests(): bool + { + return $this->numberOfTests > 0; + } + + public function hasErrors(): bool + { + return $this->numberOfErrors() > 0; + } + + public function numberOfErrors(): int + { + return $this->numberOfTestErroredEvents() + + count($this->errors) + + $this->numberOfTestsWithTestTriggeredPhpunitErrorEvents(); + } + + public function hasDeprecations(): bool + { + return $this->numberOfDeprecations() > 0; + } + + public function hasPhpOrUserDeprecations(): bool + { + return $this->numberOfPhpOrUserDeprecations() > 0; + } + + public function numberOfPhpOrUserDeprecations(): int + { + return count($this->deprecations) + + count($this->phpDeprecations); + } + + public function hasPhpunitDeprecations(): bool + { + return $this->numberOfPhpunitDeprecations() > 0; + } + + public function numberOfPhpunitDeprecations(): int + { + return count($this->testTriggeredPhpunitDeprecationEvents) + + count($this->testRunnerTriggeredDeprecationEvents); + } + + public function hasPhpunitWarnings(): bool + { + return $this->numberOfPhpunitWarnings() > 0; + } + + public function numberOfPhpunitWarnings(): int + { + return count($this->testTriggeredPhpunitWarningEvents) + + count($this->testRunnerTriggeredWarningEvents); + } + + public function numberOfDeprecations(): int + { + return count($this->deprecations) + + count($this->phpDeprecations) + + count($this->testTriggeredPhpunitDeprecationEvents) + + count($this->testRunnerTriggeredDeprecationEvents); + } + + public function hasNotices(): bool + { + return $this->numberOfNotices() > 0; + } + + public function numberOfNotices(): int + { + return count($this->notices) + + count($this->phpNotices); + } + + public function hasWarnings(): bool + { + return $this->numberOfWarnings() > 0; + } + + public function numberOfWarnings(): int + { + return count($this->warnings) + + count($this->phpWarnings); + } + + public function hasIncompleteTests(): bool + { + return $this->testMarkedIncompleteEvents !== []; + } + + public function hasRiskyTests(): bool + { + return $this->testConsideredRiskyEvents !== []; + } + + public function hasSkippedTests(): bool + { + return $this->testSkippedEvents !== []; + } + + public function hasIssuesIgnoredByBaseline(): bool + { + return $this->numberOfIssuesIgnoredByBaseline > 0; + } + + /** + * @return non-negative-int + */ + public function numberOfIssuesIgnoredByBaseline(): int + { + return $this->numberOfIssuesIgnoredByBaseline; + } + + public function hasPhpunitNotices(): bool + { + return $this->numberOfPhpunitNotices() > 0; + } + + public function numberOfPhpunitNotices(): int + { + return $this->numberOfTestsWithTestTriggeredPhpunitNoticeEvents() + + $this->numberOfTestRunnerTriggeredNoticeEvents(); + } +} diff --git a/src/Runner/TestSuiteLoader.php b/src/Runner/TestSuiteLoader.php new file mode 100644 index 00000000000..3d01964deaa --- /dev/null +++ b/src/Runner/TestSuiteLoader.php @@ -0,0 +1,142 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_diff; +use function basename; +use function get_declared_classes; +use function realpath; +use function str_ends_with; +use function strpos; +use function strtolower; +use function substr; +use PHPUnit\Framework\TestCase; +use ReflectionClass; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteLoader +{ + /** + * @var list + */ + private static array $declaredClasses = []; + + /** + * @var array> + */ + private static array $fileToClassesMap = []; + + /** + * @throws Exception + * + * @return ReflectionClass + */ + public function load(string $suiteClassFile): ReflectionClass + { + $suiteClassFile = realpath($suiteClassFile); + $suiteClassName = $this->classNameFromFileName($suiteClassFile); + $loadedClasses = $this->loadSuiteClassFile($suiteClassFile); + + foreach ($loadedClasses as $className) { + /** @noinspection PhpUnhandledExceptionInspection */ + $class = new ReflectionClass($className); + + if ($class->isAnonymous()) { + continue; + } + + if ($class->getFileName() !== $suiteClassFile) { + continue; + } + + if (!$class->isSubclassOf(TestCase::class)) { + continue; + } + + if (!str_ends_with(strtolower($class->getShortName()), strtolower($suiteClassName))) { + continue; + } + + if (!$class->isAbstract()) { + return $class; + } + + $e = new ClassIsAbstractException($class->getName(), $suiteClassFile); + } + + if (isset($e)) { + throw $e; + } + + foreach ($loadedClasses as $className) { + if (str_ends_with(strtolower($className), strtolower($suiteClassName))) { + throw new ClassDoesNotExtendTestCaseException($className, $suiteClassFile); + } + } + + throw new ClassCannotBeFoundException($suiteClassName, $suiteClassFile); + } + + private function classNameFromFileName(string $suiteClassFile): string + { + $className = basename($suiteClassFile, '.php'); + $dotPos = strpos($className, '.'); + + if ($dotPos !== false) { + $className = substr($className, 0, $dotPos); + } + + return $className; + } + + /** + * @return array + */ + private function loadSuiteClassFile(string $suiteClassFile): array + { + if (isset(self::$fileToClassesMap[$suiteClassFile])) { + return self::$fileToClassesMap[$suiteClassFile]; + } + + if (self::$declaredClasses === []) { + self::$declaredClasses = get_declared_classes(); + } + + require_once $suiteClassFile; + + $loadedClasses = array_diff( + get_declared_classes(), + self::$declaredClasses, + ); + + foreach ($loadedClasses as $loadedClass) { + /** @noinspection PhpUnhandledExceptionInspection */ + $class = new ReflectionClass($loadedClass); + + if (!isset(self::$fileToClassesMap[$class->getFileName()])) { + self::$fileToClassesMap[$class->getFileName()] = []; + } + + self::$fileToClassesMap[$class->getFileName()][] = $class->getName(); + } + + self::$declaredClasses = get_declared_classes(); + + if ($loadedClasses === []) { + return self::$declaredClasses; + } + + return $loadedClasses; + } +} diff --git a/src/Runner/TestSuiteSorter.php b/src/Runner/TestSuiteSorter.php new file mode 100644 index 00000000000..821b81e4582 --- /dev/null +++ b/src/Runner/TestSuiteSorter.php @@ -0,0 +1,313 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_diff; +use function array_merge; +use function array_reverse; +use function array_splice; +use function assert; +use function count; +use function in_array; +use function max; +use function shuffle; +use function usort; +use PHPUnit\Framework\DataProviderTestSuite; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\Test; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\ResultCache\NullResultCache; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\ResultCache\ResultCacheId; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestSuiteSorter +{ + public const int ORDER_DEFAULT = 0; + public const int ORDER_RANDOMIZED = 1; + public const int ORDER_REVERSED = 2; + public const int ORDER_DEFECTS_FIRST = 3; + public const int ORDER_DURATION = 4; + public const int ORDER_SIZE = 5; + + /** + * @var non-empty-array + */ + private const array SIZE_SORT_WEIGHT = [ + 'small' => 1, + 'medium' => 2, + 'large' => 3, + 'unknown' => 4, + ]; + + /** + * @var array Associative array of (string => DEFECT_SORT_WEIGHT) elements + */ + private array $defectSortOrder = []; + private readonly ResultCache $cache; + + public function __construct(?ResultCache $cache = null) + { + $this->cache = $cache ?? new NullResultCache; + } + + /** + * @throws Exception + */ + public function reorderTestsInSuite(Test $suite, int $order, bool $resolveDependencies, int $orderDefects): void + { + $allowedOrders = [ + self::ORDER_DEFAULT, + self::ORDER_REVERSED, + self::ORDER_RANDOMIZED, + self::ORDER_DURATION, + self::ORDER_SIZE, + ]; + + if (!in_array($order, $allowedOrders, true)) { + // @codeCoverageIgnoreStart + throw new InvalidOrderException; + // @codeCoverageIgnoreEnd + } + + $allowedOrderDefects = [ + self::ORDER_DEFAULT, + self::ORDER_DEFECTS_FIRST, + ]; + + if (!in_array($orderDefects, $allowedOrderDefects, true)) { + // @codeCoverageIgnoreStart + throw new InvalidOrderException; + // @codeCoverageIgnoreEnd + } + + if ($suite instanceof TestSuite) { + foreach ($suite as $_suite) { + $this->reorderTestsInSuite($_suite, $order, $resolveDependencies, $orderDefects); + } + + if ($orderDefects === self::ORDER_DEFECTS_FIRST) { + $this->addSuiteToDefectSortOrder($suite); + } + + $this->sort($suite, $order, $resolveDependencies, $orderDefects); + } + } + + private function sort(TestSuite $suite, int $order, bool $resolveDependencies, int $orderDefects): void + { + if ($suite->tests() === []) { + return; + } + + if ($order === self::ORDER_REVERSED) { + $suite->setTests($this->reverse($suite->tests())); + } elseif ($order === self::ORDER_RANDOMIZED) { + $suite->setTests($this->randomize($suite->tests())); + } elseif ($order === self::ORDER_DURATION) { + $suite->setTests($this->sortByDuration($suite->tests())); + } elseif ($order === self::ORDER_SIZE) { + $suite->setTests($this->sortBySize($suite->tests())); + } + + if ($orderDefects === self::ORDER_DEFECTS_FIRST) { + $suite->setTests($this->sortDefectsFirst($suite->tests())); + } + + if ($resolveDependencies && !($suite instanceof DataProviderTestSuite)) { + $tests = $suite->tests(); + + /** @noinspection PhpParamsInspection */ + /** @phpstan-ignore argument.type */ + $suite->setTests($this->resolveDependencies($tests)); + } + } + + private function addSuiteToDefectSortOrder(TestSuite $suite): void + { + $max = 0; + + foreach ($suite->tests() as $test) { + if (!$test instanceof Reorderable) { + continue; + } + + $sortId = $test->sortId(); + + if (!isset($this->defectSortOrder[$sortId])) { + $this->defectSortOrder[$sortId] = $this->cache->status(ResultCacheId::fromReorderable($test))->asInt(); + $max = max($max, $this->defectSortOrder[$sortId]); + } + } + + $this->defectSortOrder[$suite->sortId()] = $max; + } + + /** + * @param list $tests + * + * @return list + */ + private function reverse(array $tests): array + { + return array_reverse($tests); + } + + /** + * @param list $tests + * + * @return list + */ + private function randomize(array $tests): array + { + shuffle($tests); + + return $tests; + } + + /** + * @param list $tests + * + * @return list + */ + private function sortDefectsFirst(array $tests): array + { + usort( + $tests, + fn (Test $left, Test $right) => $this->cmpDefectPriorityAndTime($left, $right), + ); + + return $tests; + } + + /** + * @param list $tests + * + * @return list + */ + private function sortByDuration(array $tests): array + { + usort( + $tests, + fn (Test $left, Test $right) => $this->cmpDuration($left, $right), + ); + + return $tests; + } + + /** + * @param list $tests + * + * @return list + */ + private function sortBySize(array $tests): array + { + usort( + $tests, + fn (Test $left, Test $right) => $this->cmpSize($left, $right), + ); + + return $tests; + } + + /** + * Comparator callback function to sort tests for "reach failure as fast as possible". + * + * 1. sort tests by defect weight defined in self::DEFECT_SORT_WEIGHT + * 2. when tests are equally defective, sort the fastest to the front + * 3. do not reorder successful tests + */ + private function cmpDefectPriorityAndTime(Test $a, Test $b): int + { + assert($a instanceof Reorderable); + assert($b instanceof Reorderable); + + $priorityA = $this->defectSortOrder[$a->sortId()] ?? 0; + $priorityB = $this->defectSortOrder[$b->sortId()] ?? 0; + + if (($priorityB <=> $priorityA) > 0) { + // Sort defect weight descending + return $priorityB <=> $priorityA; + } + + if ($priorityA > 0 || $priorityB > 0) { + return $this->cmpDuration($a, $b); + } + + // do not change execution order + return 0; + } + + /** + * Compares test duration for sorting tests by duration ascending. + */ + private function cmpDuration(Test $a, Test $b): int + { + if (!($a instanceof Reorderable && $b instanceof Reorderable)) { + return 0; + } + + return $this->cache->time(ResultCacheId::fromReorderable($a)) <=> $this->cache->time(ResultCacheId::fromReorderable($b)); + } + + /** + * Compares test size for sorting tests small->medium->large->unknown. + */ + private function cmpSize(Test $a, Test $b): int + { + $sizeA = ($a instanceof TestCase || $a instanceof DataProviderTestSuite) + ? $a->size()->asString() + : 'unknown'; + $sizeB = ($b instanceof TestCase || $b instanceof DataProviderTestSuite) + ? $b->size()->asString() + : 'unknown'; + + return self::SIZE_SORT_WEIGHT[$sizeA] <=> self::SIZE_SORT_WEIGHT[$sizeB]; + } + + /** + * Reorder Tests within a TestCase in such a way as to resolve as many dependencies as possible. + * The algorithm will leave the tests in original running order when it can. + * For more details see the documentation for test dependencies. + * + * Short description of algorithm: + * 1. Pick the next Test from remaining tests to be checked for dependencies. + * 2. If the test has no dependencies: mark done, start again from the top + * 3. If the test has dependencies but none left to do: mark done, start again from the top + * 4. When we reach the end add any leftover tests to the end. These will be marked 'skipped' during execution. + * + * @param array $tests + * + * @return array + */ + private function resolveDependencies(array $tests): array + { + $newTestOrder = []; + $i = 0; + $provided = []; + + do { + if ([] === array_diff($tests[$i]->requires(), $provided)) { + $provided = array_merge($provided, $tests[$i]->provides()); + $newTestOrder = array_merge($newTestOrder, array_splice($tests, $i, 1)); + $i = 0; + } else { + $i++; + } + } while ($tests !== [] && ($i < count($tests))); + + return array_merge($newTestOrder, $tests); + } +} diff --git a/src/Runner/Version.php b/src/Runner/Version.php new file mode 100644 index 00000000000..3820aa58090 --- /dev/null +++ b/src/Runner/Version.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use function array_slice; +use function assert; +use function dirname; +use function explode; +use function implode; +use function str_contains; +use SebastianBergmann\Version as VersionId; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Version +{ + private static string $pharVersion = ''; + private static string $version = ''; + + /** + * @return non-empty-string + */ + public static function id(): string + { + if (self::$pharVersion !== '') { + return self::$pharVersion; + } + + if (self::$version === '') { + self::$version = new VersionId('13.0', dirname(__DIR__, 2))->asString(); + } + + return self::$version; + } + + /** + * @return non-empty-string + */ + public static function series(): string + { + if (str_contains(self::id(), '-')) { + $version = explode('-', self::id(), 2)[0]; + } else { + $version = self::id(); + } + + return implode('.', array_slice(explode('.', $version), 0, 2)); + } + + /** + * @return positive-int + */ + public static function majorVersionNumber(): int + { + $majorVersion = (int) explode('.', self::series())[0]; + assert($majorVersion > 0); + + return $majorVersion; + } + + /** + * @return non-empty-string + */ + public static function getVersionString(): string + { + return 'PHPUnit ' . self::id() . ' by Sebastian Bergmann and contributors.'; + } +} diff --git a/src/TextUI/Application.php b/src/TextUI/Application.php new file mode 100644 index 00000000000..e430df7c7b0 --- /dev/null +++ b/src/TextUI/Application.php @@ -0,0 +1,862 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use const PHP_EOL; +use const PHP_VERSION; +use function assert; +use function class_exists; +use function defined; +use function dirname; +use function explode; +use function function_exists; +use function is_file; +use function method_exists; +use function printf; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function trim; +use function unlink; +use PHPUnit\Event\EventFacadeIsSealedException; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Event\UnknownSubscriberTypeException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Logging\EventLogger; +use PHPUnit\Logging\JUnit\JunitXmlLogger; +use PHPUnit\Logging\OpenTestReporting\CannotOpenUriForWritingException; +use PHPUnit\Logging\OpenTestReporting\OtrXmlLogger; +use PHPUnit\Logging\TeamCity\TeamCityLogger; +use PHPUnit\Logging\TestDox\HtmlRenderer as TestDoxHtmlRenderer; +use PHPUnit\Logging\TestDox\PlainTextRenderer as TestDoxTextRenderer; +use PHPUnit\Logging\TestDox\TestResultCollector as TestDoxResultCollector; +use PHPUnit\Runner\Baseline\CannotLoadBaselineException; +use PHPUnit\Runner\Baseline\Generator as BaselineGenerator; +use PHPUnit\Runner\Baseline\Reader; +use PHPUnit\Runner\Baseline\Writer; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\Runner\CodeCoverageInitializationStatus; +use PHPUnit\Runner\DeprecationCollector\Facade as DeprecationCollector; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\Runner\ErrorHandler; +use PHPUnit\Runner\Extension\ExtensionBootstrapper; +use PHPUnit\Runner\Extension\Facade as ExtensionFacade; +use PHPUnit\Runner\Extension\PharLoader; +use PHPUnit\Runner\GarbageCollection\GarbageCollectionHandler; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use PHPUnit\Runner\ResultCache\DefaultResultCache; +use PHPUnit\Runner\ResultCache\NullResultCache; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\ResultCache\ResultCacheHandler; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Runner\Version; +use PHPUnit\TestRunner\IssueFilter; +use PHPUnit\TestRunner\TestResult\Facade as TestResultFacade; +use PHPUnit\TextUI\CliArguments\Builder; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception as ArgumentsException; +use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; +use PHPUnit\TextUI\Command\AtLeastVersionCommand; +use PHPUnit\TextUI\Command\CheckPhpConfigurationCommand; +use PHPUnit\TextUI\Command\GenerateConfigurationCommand; +use PHPUnit\TextUI\Command\ListGroupsCommand; +use PHPUnit\TextUI\Command\ListTestFilesCommand; +use PHPUnit\TextUI\Command\ListTestsAsTextCommand; +use PHPUnit\TextUI\Command\ListTestsAsXmlCommand; +use PHPUnit\TextUI\Command\ListTestSuitesCommand; +use PHPUnit\TextUI\Command\MigrateConfigurationCommand; +use PHPUnit\TextUI\Command\Result; +use PHPUnit\TextUI\Command\ShowHelpCommand; +use PHPUnit\TextUI\Command\ShowVersionCommand; +use PHPUnit\TextUI\Command\VersionCheckCommand; +use PHPUnit\TextUI\Command\WarmCodeCoverageCacheCommand; +use PHPUnit\TextUI\Configuration\BootstrapLoader; +use PHPUnit\TextUI\Configuration\BootstrapScriptDoesNotExistException; +use PHPUnit\TextUI\Configuration\BootstrapScriptException; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\PhpHandler; +use PHPUnit\TextUI\Configuration\Registry; +use PHPUnit\TextUI\Configuration\TestSuiteBuilder; +use PHPUnit\TextUI\Output\DefaultPrinter; +use PHPUnit\TextUI\Output\Facade as OutputFacade; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; +use PHPUnit\TextUI\XmlConfiguration\Loader; +use PHPUnit\Util\Http\PhpDownloader; +use SebastianBergmann\Timer\Timer; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Application +{ + /** + * @param list $argv + */ + public function run(array $argv): int + { + $this->preload(); + + try { + EventFacade::emitter()->applicationStarted(); + + $cliConfiguration = $this->buildCliConfiguration($argv); + $pathToXmlConfigurationFile = (new XmlConfigurationFileFinder)->find($cliConfiguration); + + $this->executeCommandsThatOnlyRequireCliConfiguration($cliConfiguration, $pathToXmlConfigurationFile); + + $xmlConfiguration = $this->loadXmlConfiguration($pathToXmlConfigurationFile); + + $configuration = Registry::init( + $cliConfiguration, + $xmlConfiguration, + ); + + (new PhpHandler)->handle($configuration->php()); + + try { + (new BootstrapLoader)->handle($configuration); + } catch (BootstrapScriptDoesNotExistException|BootstrapScriptException $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + + $this->executeCommandsThatDoNotRequireTheTestSuite($configuration, $cliConfiguration); + + $pharExtensions = null; + $extensionRequiresCodeCoverageCollection = false; + $extensionReplacesOutput = false; + $extensionReplacesProgressOutput = false; + $extensionReplacesResultOutput = false; + + if (!$configuration->noExtensions()) { + if ($configuration->hasPharExtensionDirectory()) { + $pharExtensions = (new PharLoader)->loadPharExtensionsInDirectory( + $configuration->pharExtensionDirectory(), + ); + } + + $bootstrappedExtensions = $this->bootstrapExtensions($configuration); + $extensionRequiresCodeCoverageCollection = $bootstrappedExtensions['requiresCodeCoverageCollection']; + $extensionReplacesOutput = $bootstrappedExtensions['replacesOutput']; + $extensionReplacesProgressOutput = $bootstrappedExtensions['replacesProgressOutput']; + $extensionReplacesResultOutput = $bootstrappedExtensions['replacesResultOutput']; + } + + $printer = OutputFacade::init( + $configuration, + $extensionReplacesProgressOutput, + $extensionReplacesResultOutput, + ); + + if ($configuration->debug()) { + EventFacade::instance()->registerTracer( + new EventLogger( + 'php://stdout', + $configuration->withTelemetry(), + ), + ); + } + + TestResultFacade::init(); + DeprecationCollector::init(); + + $this->registerLogfileWriters($configuration); + + $testDoxResultCollector = $this->testDoxResultCollector($configuration); + + $resultCache = $this->initializeTestResultCache($configuration); + + if ($configuration->controlGarbageCollector()) { + new GarbageCollectionHandler( + EventFacade::instance(), + $configuration->numberOfTestsBeforeGarbageCollection(), + ); + } + + $baselineGenerator = $this->configureBaseline($configuration); + + EventFacade::instance()->seal(); + + ErrorHandler::instance()->registerDeprecationHandler(); + + $testSuite = $this->buildTestSuite($configuration); + + ErrorHandler::instance()->restoreDeprecationHandler(); + + $this->executeCommandsThatRequireTheTestSuite($configuration, $cliConfiguration, $testSuite); + + if ($testSuite->isEmpty() && !$configuration->hasCliArguments() && $configuration->testSuite()->isEmpty()) { + $this->execute(new ShowHelpCommand(Result::FAILURE)); + } + + $coverageInitializationStatus = CodeCoverage::instance()->init( + $configuration, + CodeCoverageFilterRegistry::instance(), + $extensionRequiresCodeCoverageCollection, + ); + + if (!$configuration->debug() && !$extensionReplacesOutput) { + $this->writeRuntimeInformation($printer, $configuration); + $this->writePharExtensionInformation($printer, $pharExtensions); + $this->writeRandomSeedInformation($printer, $configuration); + + $printer->print(PHP_EOL); + } + + $this->configureDeprecationTriggers($configuration); + + $timer = new Timer; + $timer->start(); + + if ($coverageInitializationStatus === CodeCoverageInitializationStatus::NOT_REQUESTED || + $coverageInitializationStatus === CodeCoverageInitializationStatus::SUCCEEDED) { + $runner = new TestRunner; + + $runner->run( + $configuration, + $resultCache, + $testSuite, + ); + } + + $duration = $timer->stop(); + + $testDoxResult = null; + + if (isset($testDoxResultCollector)) { + $testDoxResult = $testDoxResultCollector->testMethodsGroupedByClass(); + } + + if ($testDoxResult !== null && + $configuration->hasLogfileTestdoxHtml()) { + try { + OutputFacade::printerFor($configuration->logfileTestdoxHtml())->print( + (new TestDoxHtmlRenderer)->render($testDoxResult), + ); + } catch (DirectoryDoesNotExistException|InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot log test results in TestDox HTML format to "%s": %s', + $configuration->logfileTestdoxHtml(), + $e->getMessage(), + ), + ); + } + } + + if ($testDoxResult !== null && + $configuration->hasLogfileTestdoxText()) { + try { + OutputFacade::printerFor($configuration->logfileTestdoxText())->print( + (new TestDoxTextRenderer)->render($testDoxResult), + ); + } catch (DirectoryDoesNotExistException|InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot log test results in TestDox plain text format to "%s": %s', + $configuration->logfileTestdoxText(), + $e->getMessage(), + ), + ); + } + } + + $result = TestResultFacade::result(); + + if (!$extensionReplacesResultOutput && !$configuration->debug()) { + OutputFacade::printResult( + $result, + $testDoxResult, + $duration, + $configuration->hasSpecificDeprecationToStopOn(), + ); + } + + CodeCoverage::instance()->generateReports($printer, $configuration); + + if (isset($baselineGenerator)) { + (new Writer)->write( + $configuration->generateBaseline(), + $baselineGenerator->baseline(), + ); + + $printer->print( + sprintf( + PHP_EOL . 'Baseline written to %s.' . PHP_EOL, + realpath($configuration->generateBaseline()), + ), + ); + } + + $shellExitCode = (new ShellExitCodeCalculator)->calculate( + $configuration, + $result, + ); + + EventFacade::emitter()->applicationFinished($shellExitCode); + + return $shellExitCode; + // @codeCoverageIgnoreStart + } catch (Throwable $t) { + $this->exitWithCrashMessage($t); + } + // @codeCoverageIgnoreEnd + } + + private function execute(Command\Command $command, bool $requiresResultCollectedFromEvents = false): never + { + $errored = false; + + if ($requiresResultCollectedFromEvents) { + try { + TestResultFacade::init(); + EventFacade::instance()->seal(); + + $resultCollectedFromEvents = TestResultFacade::result(); + + $errored = $resultCollectedFromEvents->hasTestTriggeredPhpunitErrorEvents(); + } catch (EventFacadeIsSealedException|UnknownSubscriberTypeException) { + } + } + + print Version::getVersionString() . PHP_EOL . PHP_EOL; + + if (!$errored) { + $result = $command->execute(); + + print $result->output(); + + exit($result->shellExitCode()); + } + + assert(isset($resultCollectedFromEvents)); + + print 'There were errors:' . PHP_EOL; + + foreach ($resultCollectedFromEvents->testTriggeredPhpunitErrorEvents() as $events) { + foreach ($events as $event) { + print PHP_EOL . trim($event->message()) . PHP_EOL; + } + } + + exit(Result::EXCEPTION); + } + + /** + * @param list $argv + */ + private function buildCliConfiguration(array $argv): CliConfiguration + { + try { + $cliConfiguration = (new Builder)->fromParameters($argv); + } catch (ArgumentsException $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + + return $cliConfiguration; + } + + private function loadXmlConfiguration(false|string $configurationFile): XmlConfiguration + { + if ($configurationFile === false) { + return DefaultConfiguration::create(); + } + + try { + return (new Loader)->load($configurationFile); + } catch (Throwable $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + } + + private function buildTestSuite(Configuration $configuration): TestSuite + { + try { + return (new TestSuiteBuilder)->build($configuration); + } catch (Exception $e) { + $this->exitWithErrorMessage($e->getMessage()); + } + } + + /** + * @return array{requiresCodeCoverageCollection: bool, replacesOutput: bool, replacesProgressOutput: bool, replacesResultOutput: bool} + */ + private function bootstrapExtensions(Configuration $configuration): array + { + $facade = new ExtensionFacade; + + $extensionBootstrapper = new ExtensionBootstrapper( + $configuration, + $facade, + ); + + foreach ($configuration->extensionBootstrappers() as $bootstrapper) { + $extensionBootstrapper->bootstrap( + $bootstrapper['className'], + $bootstrapper['parameters'], + ); + } + + return [ + 'requiresCodeCoverageCollection' => $facade->requiresCodeCoverageCollection(), + 'replacesOutput' => $facade->replacesOutput(), + 'replacesProgressOutput' => $facade->replacesProgressOutput(), + 'replacesResultOutput' => $facade->replacesResultOutput(), + ]; + } + + private function executeCommandsThatOnlyRequireCliConfiguration(CliConfiguration $cliConfiguration, false|string $configurationFile): void + { + if ($cliConfiguration->generateConfiguration()) { + $this->execute(new GenerateConfigurationCommand); + } + + if ($cliConfiguration->migrateConfiguration()) { + if ($configurationFile === false) { + $this->exitWithErrorMessage('No configuration file found to migrate'); + } + + $this->execute(new MigrateConfigurationCommand(realpath($configurationFile))); + } + + if ($cliConfiguration->hasAtLeastVersion()) { + $this->execute(new AtLeastVersionCommand($cliConfiguration->atLeastVersion())); + } + + if ($cliConfiguration->version()) { + $this->execute(new ShowVersionCommand); + } + + if ($cliConfiguration->checkPhpConfiguration()) { + $this->execute(new CheckPhpConfigurationCommand); + } + + if ($cliConfiguration->checkVersion()) { + $this->execute(new VersionCheckCommand(new PhpDownloader, Version::majorVersionNumber(), Version::id())); + } + + if ($cliConfiguration->help()) { + $this->execute(new ShowHelpCommand(Result::SUCCESS)); + } + } + + private function executeCommandsThatDoNotRequireTheTestSuite(Configuration $configuration, CliConfiguration $cliConfiguration): void + { + if ($cliConfiguration->warmCoverageCache()) { + $this->execute(new WarmCodeCoverageCacheCommand($configuration, CodeCoverageFilterRegistry::instance())); + } + } + + private function executeCommandsThatRequireTheTestSuite(Configuration $configuration, CliConfiguration $cliConfiguration, TestSuite $testSuite): void + { + if ($cliConfiguration->listSuites()) { + $this->execute(new ListTestSuitesCommand($testSuite)); + } + + if ($cliConfiguration->listGroups()) { + $this->execute( + new ListGroupsCommand( + $this->filteredTests( + $configuration, + $testSuite, + ), + ), + true, + ); + } + + if ($cliConfiguration->listTests()) { + $this->execute( + new ListTestsAsTextCommand( + $this->filteredTests( + $configuration, + $testSuite, + ), + ), + true, + ); + } + + if ($cliConfiguration->hasListTestsXml()) { + $this->execute( + new ListTestsAsXmlCommand( + $this->filteredTests( + $configuration, + $testSuite, + ), + $cliConfiguration->listTestsXml(), + ), + true, + ); + } + + if ($cliConfiguration->listTestFiles()) { + $this->execute( + new ListTestFilesCommand( + $this->filteredTests( + $configuration, + $testSuite, + ), + ), + true, + ); + } + } + + private function writeRuntimeInformation(Printer $printer, Configuration $configuration): void + { + $printer->print(Version::getVersionString() . PHP_EOL . PHP_EOL); + + $runtime = 'PHP ' . PHP_VERSION; + + if (CodeCoverage::instance()->isActive()) { + $runtime .= ' with ' . CodeCoverage::instance()->driverNameAndVersion(); + } + + $this->writeMessage($printer, 'Runtime', $runtime); + + if ($configuration->hasConfigurationFile()) { + $this->writeMessage( + $printer, + 'Configuration', + $configuration->configurationFile(), + ); + } + } + + /** + * @param ?list $pharExtensions + */ + private function writePharExtensionInformation(Printer $printer, ?array $pharExtensions): void + { + if ($pharExtensions === null) { + return; + } + + foreach ($pharExtensions as $extension) { + $this->writeMessage( + $printer, + 'Extension', + $extension, + ); + } + } + + private function writeMessage(Printer $printer, string $type, string $message): void + { + $printer->print( + sprintf( + "%-15s%s\n", + $type . ':', + $message, + ), + ); + } + + private function writeRandomSeedInformation(Printer $printer, Configuration $configuration): void + { + if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { + $this->writeMessage( + $printer, + 'Random Seed', + (string) $configuration->randomOrderSeed(), + ); + } + } + + private function registerLogfileWriters(Configuration $configuration): void + { + if ($configuration->hasLogEventsText()) { + if (is_file($configuration->logEventsText())) { + unlink($configuration->logEventsText()); + } + + EventFacade::instance()->registerTracer( + new EventLogger( + $configuration->logEventsText(), + false, + ), + ); + } + + if ($configuration->hasLogEventsVerboseText()) { + if (is_file($configuration->logEventsVerboseText())) { + unlink($configuration->logEventsVerboseText()); + } + + EventFacade::instance()->registerTracer( + new EventLogger( + $configuration->logEventsVerboseText(), + true, + ), + ); + } + + if ($configuration->hasLogfileJunit()) { + try { + new JunitXmlLogger( + OutputFacade::printerFor($configuration->logfileJunit()), + EventFacade::instance(), + ); + } catch (DirectoryDoesNotExistException|InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot log test results in JUnit XML format to "%s": %s', + $configuration->logfileJunit(), + $e->getMessage(), + ), + ); + } + } + + if ($configuration->hasLogfileOtr()) { + try { + new OtrXmlLogger( + EventFacade::instance(), + $configuration->logfileOtr(), + $configuration->includeGitInformationInOtrLogfile(), + ); + } catch (CannotOpenUriForWritingException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot log test results in Open Test Reporting XML format to "%s": %s', + $configuration->logfileOtr(), + $e->getMessage(), + ), + ); + } + } + + if ($configuration->hasLogfileTeamcity()) { + try { + new TeamCityLogger( + DefaultPrinter::from( + $configuration->logfileTeamcity(), + ), + EventFacade::instance(), + ); + } catch (DirectoryDoesNotExistException|InvalidSocketException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot log test results in TeamCity format to "%s": %s', + $configuration->logfileTeamcity(), + $e->getMessage(), + ), + ); + } + } + } + + private function testDoxResultCollector(Configuration $configuration): ?TestDoxResultCollector + { + if ($configuration->hasLogfileTestdoxHtml() || + $configuration->hasLogfileTestdoxText() || + $configuration->outputIsTestDox()) { + return new TestDoxResultCollector( + EventFacade::instance(), + new IssueFilter($configuration->source()), + ); + } + + return null; + } + + private function initializeTestResultCache(Configuration $configuration): ResultCache + { + if ($configuration->cacheResult()) { + $cache = new DefaultResultCache($configuration->testResultCacheFile()); + + new ResultCacheHandler($cache, EventFacade::instance()); + + return $cache; + } + + return new NullResultCache; + } + + private function configureBaseline(Configuration $configuration): ?BaselineGenerator + { + if ($configuration->hasGenerateBaseline()) { + return new BaselineGenerator( + EventFacade::instance(), + $configuration->source(), + ); + } + + if ($configuration->source()->useBaseline()) { + $baselineFile = $configuration->source()->baseline(); + $baseline = null; + + try { + $baseline = (new Reader)->read($baselineFile); + } catch (CannotLoadBaselineException $e) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning($e->getMessage()); + } + + if ($baseline !== null) { + ErrorHandler::instance()->useBaseline($baseline); + } + } + + return null; + } + + /** + * @codeCoverageIgnore + */ + private function exitWithCrashMessage(Throwable $t): never + { + $message = $t->getMessage(); + + if (trim($message) === '') { + $message = '(no message)'; + } + + printf( + '%s%sAn error occurred inside PHPUnit.%s%sMessage: %s', + PHP_EOL, + PHP_EOL, + PHP_EOL, + PHP_EOL, + $message, + ); + + $first = true; + + if ($t->getPrevious() !== null) { + $t = $t->getPrevious(); + } + + do { + printf( + '%s%s: %s:%d%s%s%s%s', + PHP_EOL, + $first ? 'Location' : 'Caused by', + $t->getFile(), + $t->getLine(), + PHP_EOL, + PHP_EOL, + $t->getTraceAsString(), + PHP_EOL, + ); + + $first = false; + } while ($t = $t->getPrevious()); + + exit(Result::CRASH); + } + + private function exitWithErrorMessage(string $message): never + { + print Version::getVersionString() . PHP_EOL . PHP_EOL . $message . PHP_EOL; + + exit(Result::EXCEPTION); + } + + /** + * @return list + */ + private function filteredTests(Configuration $configuration, TestSuite $suite): array + { + (new TestSuiteFilterProcessor)->process($configuration, $suite); + + return $suite->collect(); + } + + private function configureDeprecationTriggers(Configuration $configuration): void + { + $deprecationTriggers = [ + 'functions' => [], + 'methods' => [], + ]; + + foreach ($configuration->source()->deprecationTriggers()['functions'] as $function) { + if (!function_exists($function)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Function %s cannot be configured as a deprecation trigger because it is not declared', + $function, + ), + ); + + continue; + } + + $deprecationTriggers['functions'][] = $function; + } + + foreach ($configuration->source()->deprecationTriggers()['methods'] as $method) { + if (!str_contains($method, '::')) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + '%s cannot be configured as a deprecation trigger because it is not in ClassName::methodName format', + $method, + ), + ); + + continue; + } + + [$className, $methodName] = explode('::', $method); + + if (!class_exists($className) || !method_exists($className, $methodName)) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Method %s::%s cannot be configured as a deprecation trigger because it is not declared', + $className, + $methodName, + ), + ); + + continue; + } + + $deprecationTriggers['methods'][] = [ + 'className' => $className, + 'methodName' => $methodName, + ]; + } + + ErrorHandler::instance()->useDeprecationTriggers($deprecationTriggers); + } + + private function preload(): void + { + if (!defined('PHPUNIT_COMPOSER_INSTALL')) { + return; + } + + $classMapFile = dirname(PHPUNIT_COMPOSER_INSTALL) . '/composer/autoload_classmap.php'; + + if (!is_file($classMapFile)) { + return; + } + + foreach (require $classMapFile as $codeUnitName => $sourceCodeFile) { + if (!str_starts_with($codeUnitName, 'PHPUnit\\') && + !str_starts_with($codeUnitName, 'SebastianBergmann\\')) { + continue; + } + + if (str_contains($sourceCodeFile, '/tests/')) { + continue; + } + + require_once $sourceCodeFile; + } + } +} diff --git a/src/TextUI/Command/Command.php b/src/TextUI/Command/Command.php new file mode 100644 index 00000000000..4194551e41a --- /dev/null +++ b/src/TextUI/Command/Command.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Command +{ + public function execute(): Result; +} diff --git a/src/TextUI/Command/Commands/AtLeastVersionCommand.php b/src/TextUI/Command/Commands/AtLeastVersionCommand.php new file mode 100644 index 00000000000..7bace86c8fd --- /dev/null +++ b/src/TextUI/Command/Commands/AtLeastVersionCommand.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use function version_compare; +use PHPUnit\Runner\Version; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class AtLeastVersionCommand implements Command +{ + private string $version; + + public function __construct(string $version) + { + $this->version = $version; + } + + public function execute(): Result + { + if (version_compare(Version::id(), $this->version, '>=')) { + return Result::from(); + } + + return Result::from('', Result::FAILURE); + } +} diff --git a/src/TextUI/Command/Commands/CheckPhpConfigurationCommand.php b/src/TextUI/Command/Commands/CheckPhpConfigurationCommand.php new file mode 100644 index 00000000000..7f684cc0e18 --- /dev/null +++ b/src/TextUI/Command/Commands/CheckPhpConfigurationCommand.php @@ -0,0 +1,166 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const E_ALL; +use const PHP_EOL; +use function extension_loaded; +use function in_array; +use function ini_get; +use function max; +use function sprintf; +use function strlen; +use PHPUnit\Runner\Version; +use PHPUnit\Util\Color; +use SebastianBergmann\Environment\Console; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CheckPhpConfigurationCommand implements Command +{ + private bool $colorize; + + public function __construct() + { + $this->colorize = (new Console)->hasColorSupport(); + } + + public function execute(): Result + { + $lines = []; + $shellExitCode = 0; + + foreach ($this->settings() as $name => $setting) { + foreach ($setting['requiredExtensions'] as $extension) { + if (!extension_loaded($extension)) { + // @codeCoverageIgnoreStart + continue 2; + // @codeCoverageIgnoreEnd + } + } + + $actualValue = ini_get($name); + + if (in_array($actualValue, $setting['expectedValues'], true)) { + $check = $this->ok(); + } else { + $check = $this->notOk($actualValue); + $shellExitCode = 1; + } + + $lines[] = [ + sprintf( + '%s = %s', + $name, + $setting['valueForConfiguration'], + ), + $check, + ]; + } + + $maxLength = 0; + + foreach ($lines as $line) { + $maxLength = max($maxLength, strlen($line[0])); + } + + $buffer = sprintf( + 'Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development' . PHP_EOL . PHP_EOL, + Version::series(), + ); + + foreach ($lines as $line) { + $buffer .= sprintf( + '%-' . $maxLength . 's ... %s' . PHP_EOL, + $line[0], + $line[1], + ); + } + + return Result::from($buffer, $shellExitCode); + } + + /** + * @return non-empty-string + */ + private function ok(): string + { + if (!$this->colorize) { + return 'ok'; + } + + // @codeCoverageIgnoreStart + return Color::colorizeTextBox('fg-green, bold', 'ok'); + // @codeCoverageIgnoreEnd + } + + /** + * @return non-empty-string + */ + private function notOk(string $actualValue): string + { + $message = sprintf('not ok (%s)', $actualValue); + + if (!$this->colorize) { + return $message; + } + + // @codeCoverageIgnoreStart + return Color::colorizeTextBox('fg-red, bold', $message); + // @codeCoverageIgnoreEnd + } + + /** + * @return non-empty-array, valueForConfiguration: non-empty-string, requiredExtensions: list}> + */ + private function settings(): array + { + return [ + 'display_errors' => [ + 'expectedValues' => ['1'], + 'valueForConfiguration' => 'On', + 'requiredExtensions' => [], + ], + 'display_startup_errors' => [ + 'expectedValues' => ['1'], + 'valueForConfiguration' => 'On', + 'requiredExtensions' => [], + ], + 'error_reporting' => [ + 'expectedValues' => ['-1', (string) E_ALL], + 'valueForConfiguration' => '-1', + 'requiredExtensions' => [], + ], + 'xdebug.show_exception_trace' => [ + 'expectedValues' => ['0'], + 'valueForConfiguration' => '0', + 'requiredExtensions' => ['xdebug'], + ], + 'zend.assertions' => [ + 'expectedValues' => ['1'], + 'valueForConfiguration' => '1', + 'requiredExtensions' => [], + ], + 'assert.exception' => [ + 'expectedValues' => ['1'], + 'valueForConfiguration' => '1', + 'requiredExtensions' => [], + ], + 'memory_limit' => [ + 'expectedValues' => ['-1'], + 'valueForConfiguration' => '-1', + 'requiredExtensions' => [], + ], + ]; + } +} diff --git a/src/TextUI/Command/Commands/GenerateConfigurationCommand.php b/src/TextUI/Command/Commands/GenerateConfigurationCommand.php new file mode 100644 index 00000000000..cb1a9ac9513 --- /dev/null +++ b/src/TextUI/Command/Commands/GenerateConfigurationCommand.php @@ -0,0 +1,122 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use const STDIN; +use function assert; +use function defined; +use function fgets; +use function file_put_contents; +use function getcwd; +use function is_file; +use function sprintf; +use function trim; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\XmlConfiguration\Generator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GenerateConfigurationCommand implements Command +{ + public function execute(): Result + { + $directory = getcwd(); + + print 'Generating phpunit.xml in ' . $directory . PHP_EOL . PHP_EOL; + print 'Bootstrap script (relative to path shown above; default: vendor/autoload.php): '; + + $bootstrapScript = $this->read(); + + print 'Tests directory (relative to path shown above; default: tests): '; + + $testsDirectory = $this->read(); + + print 'Source directory (relative to path shown above; default: src): '; + + $src = $this->read(); + + print 'Cache directory (relative to path shown above; default: .phpunit.cache): '; + + $cacheDirectory = $this->read(); + + if ($bootstrapScript === '') { + $bootstrapScript = 'vendor/autoload.php'; + } + + if ($testsDirectory === '') { + $testsDirectory = 'tests'; + } + + if ($src === '') { + $src = 'src'; + } + + if ($cacheDirectory === '') { + $cacheDirectory = '.phpunit.cache'; + } + + if (defined('PHPUNIT_COMPOSER_INSTALL') && + is_file($directory . '/vendor/phpunit/phpunit/phpunit.xsd')) { + $schemaLocation = 'vendor/phpunit/phpunit/phpunit.xsd'; + } else { + $schemaLocation = sprintf( + 'https://schema.phpunit.de/%s/phpunit.xsd', + Version::series(), + ); + } + + $generator = new Generator; + + $result = @file_put_contents( + $directory . '/phpunit.xml', + $generator->generateDefaultConfiguration( + $schemaLocation, + $bootstrapScript, + $testsDirectory, + $src, + $cacheDirectory, + ), + ); + + if ($result !== false) { + return Result::from( + sprintf( + PHP_EOL . 'Generated phpunit.xml in %s.' . PHP_EOL . + 'Make sure to exclude the %s directory from version control.' . PHP_EOL, + $directory, + $cacheDirectory, + ), + ); + } + + // @codeCoverageIgnoreStart + return Result::from( + sprintf( + PHP_EOL . 'Could not write phpunit.xml in %s.' . PHP_EOL, + $directory, + ), + Result::EXCEPTION, + ); + // @codeCoverageIgnoreEnd + } + + private function read(): string + { + $buffer = fgets(STDIN); + + assert($buffer !== false); + + return trim($buffer); + } +} diff --git a/src/TextUI/Command/Commands/ListGroupsCommand.php b/src/TextUI/Command/Commands/ListGroupsCommand.php new file mode 100644 index 00000000000..94eb1355ced --- /dev/null +++ b/src/TextUI/Command/Commands/ListGroupsCommand.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function count; +use function ksort; +use function sprintf; +use function str_starts_with; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListGroupsCommand implements Command +{ + /** + * @var list + */ + private array $tests; + + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + + public function execute(): Result + { + /** @var array $groups */ + $groups = []; + + foreach ($this->tests as $test) { + if ($test instanceof PhptTestCase) { + $_groups = ['default']; + } else { + $_groups = $test->groups(); + } + + foreach ($_groups as $group) { + if (!isset($groups[$group])) { + $groups[$group] = 1; + } else { + $groups[$group]++; + } + } + } + + ksort($groups); + + $buffer = sprintf( + 'Available test group%s:' . PHP_EOL, + count($groups) > 1 ? 's' : '', + ); + + foreach ($groups as $group => $numberOfTests) { + if (str_starts_with((string) $group, '__phpunit_')) { + continue; + } + + $buffer .= sprintf( + ' - %s (%d test%s)' . PHP_EOL, + (string) $group, + $numberOfTests, + $numberOfTests > 1 ? 's' : '', + ); + } + + return Result::from($buffer); + } +} diff --git a/src/TextUI/Command/Commands/ListTestFilesCommand.php b/src/TextUI/Command/Commands/ListTestFilesCommand.php new file mode 100644 index 00000000000..dfe2da27cf7 --- /dev/null +++ b/src/TextUI/Command/Commands/ListTestFilesCommand.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function array_unique; +use function assert; +use function sprintf; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use ReflectionException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestFilesCommand implements Command +{ + /** + * @var list + */ + private array $tests; + + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + + /** + * @throws ReflectionException + */ + public function execute(): Result + { + $buffer = 'Available test files:' . PHP_EOL; + + $results = []; + + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + $name = new ReflectionClass($test)->getFileName(); + + assert($name !== false); + + $results[] = $name; + + continue; + } + + $results[] = $test->getName(); + } + + foreach (array_unique($results) as $result) { + $buffer .= sprintf( + ' - %s' . PHP_EOL, + $result, + ); + } + + return Result::from($buffer); + } +} diff --git a/src/TextUI/Command/Commands/ListTestSuitesCommand.php b/src/TextUI/Command/Commands/ListTestSuitesCommand.php new file mode 100644 index 00000000000..fcaf7765a37 --- /dev/null +++ b/src/TextUI/Command/Commands/ListTestSuitesCommand.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function count; +use function ksort; +use function sprintf; +use PHPUnit\Framework\TestSuite; +use PHPUnit\TextUI\Configuration\Registry; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestSuitesCommand implements Command +{ + private TestSuite $testSuite; + + public function __construct(TestSuite $testSuite) + { + $this->testSuite = $testSuite; + } + + public function execute(): Result + { + /** @var array $suites */ + $suites = []; + + foreach ($this->testSuite->tests() as $test) { + assert($test instanceof TestSuite); + + $suites[$test->name()] = count($test->collect()); + } + + ksort($suites); + + $buffer = $this->warnAboutConflictingOptions(); + + $buffer .= sprintf( + 'Available test suite%s:' . PHP_EOL, + count($suites) > 1 ? 's' : '', + ); + + foreach ($suites as $suite => $numberOfTests) { + $buffer .= sprintf( + ' - %s (%d test%s)' . PHP_EOL, + $suite, + $numberOfTests, + $numberOfTests > 1 ? 's' : '', + ); + } + + return Result::from($buffer); + } + + private function warnAboutConflictingOptions(): string + { + $buffer = ''; + + $configuration = Registry::get(); + + if ($configuration->includeTestSuites() !== [] && !$configuration->hasDefaultTestSuite()) { + $buffer .= 'The --testsuite and --list-suites options cannot be combined, --testsuite is ignored' . PHP_EOL; + } + + if ($configuration->hasFilter()) { + $buffer .= 'The --filter and --list-suites options cannot be combined, --filter is ignored' . PHP_EOL; + } + + if ($configuration->hasGroups()) { + $buffer .= 'The --group (CLI) and (XML) options cannot be combined with --list-suites, --group and are ignored' . PHP_EOL; + } + + if ($configuration->hasExcludeGroups()) { + $buffer .= 'The --exclude-group (CLI) and (XML) options cannot be combined with --list-suites, --exclude-group and are ignored' . PHP_EOL; + } + + if ($buffer !== '') { + $buffer .= PHP_EOL; + } + + return $buffer; + } +} diff --git a/src/TextUI/Command/Commands/ListTestsAsTextCommand.php b/src/TextUI/Command/Commands/ListTestsAsTextCommand.php new file mode 100644 index 00000000000..c3d71b5d237 --- /dev/null +++ b/src/TextUI/Command/Commands/ListTestsAsTextCommand.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function count; +use function sprintf; +use function str_replace; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestsAsTextCommand implements Command +{ + /** + * @var list + */ + private array $tests; + + /** + * @param list $tests + */ + public function __construct(array $tests) + { + $this->tests = $tests; + } + + public function execute(): Result + { + $buffer = sprintf( + 'Available test%s:' . PHP_EOL, + count($this->tests) > 1 ? 's' : '', + ); + + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + $name = sprintf( + '%s::%s', + $test::class, + str_replace(' with data set ', '', $test->nameWithDataSet()), + ); + } else { + $name = $test->getName(); + } + + $buffer .= sprintf( + ' - %s' . PHP_EOL, + $name, + ); + } + + return Result::from($buffer); + } +} diff --git a/src/TextUI/Command/Commands/ListTestsAsXmlCommand.php b/src/TextUI/Command/Commands/ListTestsAsXmlCommand.php new file mode 100644 index 00000000000..a07c62cbb02 --- /dev/null +++ b/src/TextUI/Command/Commands/ListTestsAsXmlCommand.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function file_put_contents; +use function ksort; +use function sprintf; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Phpt\TestCase as PhptTestCase; +use ReflectionClass; +use XMLWriter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ListTestsAsXmlCommand implements Command +{ + /** + * @var list + */ + private array $tests; + private string $filename; + + /** + * @param list $tests + */ + public function __construct(array $tests, string $filename) + { + $this->tests = $tests; + $this->filename = $filename; + } + + public function execute(): Result + { + $writer = new XMLWriter; + + $writer->openMemory(); + $writer->setIndent(true); + $writer->startDocument(); + + $writer->startElement('testSuite'); + $writer->writeAttribute('xmlns', 'https://xml.phpunit.de/testSuite'); + + $writer->startElement('tests'); + + $currentTestClass = null; + $groups = []; + + foreach ($this->tests as $test) { + if ($test instanceof TestCase) { + foreach ($test->groups() as $group) { + if (!isset($groups[$group])) { + $groups[$group] = []; + } + + $groups[$group][] = $test->valueObjectForEvents()->id(); + } + + if ($test::class !== $currentTestClass) { + if ($currentTestClass !== null) { + $writer->endElement(); + } + + $file = new ReflectionClass($test)->getFileName(); + + assert($file !== false); + + $writer->startElement('testClass'); + $writer->writeAttribute('name', $test::class); + $writer->writeAttribute('file', $file); + + $currentTestClass = $test::class; + } + + $writer->startElement('testMethod'); + $writer->writeAttribute('id', $test->valueObjectForEvents()->id()); + $writer->writeAttribute('name', $test->valueObjectForEvents()->methodName()); + $writer->endElement(); + + continue; + } + + if ($currentTestClass !== null) { + $writer->endElement(); + + $currentTestClass = null; + } + + $writer->startElement('phpt'); + $writer->writeAttribute('file', $test->getName()); + $writer->endElement(); + } + + if ($currentTestClass !== null) { + $writer->endElement(); + } + + $writer->endElement(); + + ksort($groups); + + $writer->startElement('groups'); + + foreach ($groups as $groupName => $testIds) { + $writer->startElement('group'); + $writer->writeAttribute('name', (string) $groupName); + + foreach ($testIds as $testId) { + $writer->startElement('test'); + $writer->writeAttribute('id', $testId); + $writer->endElement(); + } + + $writer->endElement(); + } + + $writer->endElement(); + $writer->endElement(); + + file_put_contents($this->filename, $writer->outputMemory()); + + return Result::from( + sprintf( + 'Wrote list of tests that would have been run to %s' . PHP_EOL, + $this->filename, + ), + ); + } +} diff --git a/src/TextUI/Command/Commands/MigrateConfigurationCommand.php b/src/TextUI/Command/Commands/MigrateConfigurationCommand.php new file mode 100644 index 00000000000..507ff90f346 --- /dev/null +++ b/src/TextUI/Command/Commands/MigrateConfigurationCommand.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function copy; +use function file_put_contents; +use function sprintf; +use PHPUnit\TextUI\XmlConfiguration\Migrator; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MigrateConfigurationCommand implements Command +{ + private string $filename; + + public function __construct(string $filename) + { + $this->filename = $filename; + } + + public function execute(): Result + { + try { + $migrated = (new Migrator)->migrate($this->filename); + + copy($this->filename, $this->filename . '.bak'); + + file_put_contents($this->filename, $migrated); + + return Result::from( + sprintf( + 'Created backup: %s.bak%sMigrated configuration: %s%s', + $this->filename, + PHP_EOL, + $this->filename, + PHP_EOL, + ), + ); + } catch (Throwable $t) { + return Result::from( + sprintf( + 'Migration of %s failed:%s%s%s', + $this->filename, + PHP_EOL, + $t->getMessage(), + PHP_EOL, + ), + Result::FAILURE, + ); + } + } +} diff --git a/src/TextUI/Command/Commands/ShowHelpCommand.php b/src/TextUI/Command/Commands/ShowHelpCommand.php new file mode 100644 index 00000000000..1fd04811fc7 --- /dev/null +++ b/src/TextUI/Command/Commands/ShowHelpCommand.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use PHPUnit\TextUI\Help; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShowHelpCommand implements Command +{ + private int $shellExitCode; + + public function __construct(int $shellExitCode) + { + $this->shellExitCode = $shellExitCode; + } + + public function execute(): Result + { + return Result::from( + (new Help)->generate(), + $this->shellExitCode, + ); + } +} diff --git a/src/TextUI/Command/Commands/ShowVersionCommand.php b/src/TextUI/Command/Commands/ShowVersionCommand.php new file mode 100644 index 00000000000..4455a3d2359 --- /dev/null +++ b/src/TextUI/Command/Commands/ShowVersionCommand.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShowVersionCommand implements Command +{ + public function execute(): Result + { + return Result::from(); + } +} diff --git a/src/TextUI/Command/Commands/VersionCheckCommand.php b/src/TextUI/Command/Commands/VersionCheckCommand.php new file mode 100644 index 00000000000..3e076ebeedc --- /dev/null +++ b/src/TextUI/Command/Commands/VersionCheckCommand.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function assert; +use function sprintf; +use function version_compare; +use PHPUnit\Util\Http\Downloader; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class VersionCheckCommand implements Command +{ + private Downloader $downloader; + private int $majorVersionNumber; + private string $versionId; + + public function __construct(Downloader $downloader, int $majorVersionNumber, string $versionId) + { + $this->downloader = $downloader; + $this->majorVersionNumber = $majorVersionNumber; + $this->versionId = $versionId; + } + + public function execute(): Result + { + $latestVersion = $this->downloader->download('https://phar.phpunit.de/latest-version-of/phpunit'); + + assert($latestVersion !== false); + + $latestCompatibleVersion = $this->downloader->download('https://phar.phpunit.de/latest-version-of/phpunit-' . $this->majorVersionNumber); + + $notLatest = version_compare($latestVersion, $this->versionId, '>'); + $notLatestCompatible = false; + + if ($latestCompatibleVersion !== false) { + $notLatestCompatible = version_compare($latestCompatibleVersion, $this->versionId, '>'); + } + + if (!$notLatest && !$notLatestCompatible) { + return Result::from( + 'You are using the latest version of PHPUnit.' . PHP_EOL, + ); + } + + $buffer = 'You are not using the latest version of PHPUnit.' . PHP_EOL; + + if ($notLatestCompatible) { + $buffer .= sprintf( + 'The latest version compatible with PHPUnit %s is PHPUnit %s.' . PHP_EOL, + $this->versionId, + $latestCompatibleVersion, + ); + } + + if ($notLatest) { + $buffer .= sprintf( + 'The latest version is PHPUnit %s.' . PHP_EOL, + $latestVersion, + ); + } + + return Result::from($buffer, Result::FAILURE); + } +} diff --git a/src/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php b/src/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php new file mode 100644 index 00000000000..7d1afafe322 --- /dev/null +++ b/src/TextUI/Command/Commands/WarmCodeCoverageCacheCommand.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use function printf; +use PHPUnit\TextUI\Configuration\CodeCoverageFilterRegistry; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\NoCoverageCacheDirectoryException; +use SebastianBergmann\CodeCoverage\StaticAnalysis\CacheWarmer; +use SebastianBergmann\Timer\NoActiveTimerException; +use SebastianBergmann\Timer\Timer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final readonly class WarmCodeCoverageCacheCommand implements Command +{ + private Configuration $configuration; + private CodeCoverageFilterRegistry $codeCoverageFilterRegistry; + + public function __construct(Configuration $configuration, CodeCoverageFilterRegistry $codeCoverageFilterRegistry) + { + $this->configuration = $configuration; + $this->codeCoverageFilterRegistry = $codeCoverageFilterRegistry; + } + + /** + * @throws NoActiveTimerException + * @throws NoCoverageCacheDirectoryException + */ + public function execute(): Result + { + if (!$this->configuration->hasCoverageCacheDirectory()) { + return Result::from( + 'Cache for static analysis has not been configured' . PHP_EOL, + Result::FAILURE, + ); + } + + $this->codeCoverageFilterRegistry->init($this->configuration, true); + + if (!$this->codeCoverageFilterRegistry->configured()) { + return Result::from( + 'Filter for code coverage has not been configured' . PHP_EOL, + Result::FAILURE, + ); + } + + $timer = new Timer; + $timer->start(); + + print 'Warming cache for static analysis ... '; + + /** @phpstan-ignore new.internalClass,method.internalClass */ + $statistics = (new CacheWarmer)->warmCache( + $this->configuration->coverageCacheDirectory(), + !$this->configuration->disableCodeCoverageIgnore(), + $this->configuration->ignoreDeprecatedCodeUnitsFromCodeCoverage(), + $this->codeCoverageFilterRegistry->get(), + ); + + printf( + '[%s]%s%s%d file%s processed, %d cache hit%s, %d cache miss%s%s', + $timer->stop()->asString(), + PHP_EOL, + PHP_EOL, + $statistics['cacheHits'] + $statistics['cacheMisses'], + ($statistics['cacheHits'] + $statistics['cacheMisses']) !== 1 ? 's' : '', + $statistics['cacheHits'], + $statistics['cacheHits'] !== 1 ? 's' : '', + $statistics['cacheMisses'], + $statistics['cacheMisses'] !== 1 ? 'es' : '', + PHP_EOL, + ); + + return Result::from(); + } +} diff --git a/src/TextUI/Command/Result.php b/src/TextUI/Command/Result.php new file mode 100644 index 00000000000..ae4a3e27fe8 --- /dev/null +++ b/src/TextUI/Command/Result.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Result +{ + public const int SUCCESS = 0; + public const int FAILURE = 1; + public const int EXCEPTION = 2; + public const int CRASH = 255; + private string $output; + private int $shellExitCode; + + public static function from(string $output = '', int $shellExitCode = self::SUCCESS): self + { + return new self($output, $shellExitCode); + } + + private function __construct(string $output, int $shellExitCode) + { + $this->output = $output; + $this->shellExitCode = $shellExitCode; + } + + public function output(): string + { + return $this->output; + } + + public function shellExitCode(): int + { + return $this->shellExitCode; + } +} diff --git a/src/TextUI/Configuration/BootstrapLoader.php b/src/TextUI/Configuration/BootstrapLoader.php new file mode 100644 index 00000000000..f52d66475bd --- /dev/null +++ b/src/TextUI/Configuration/BootstrapLoader.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PHP_EOL; +use function in_array; +use function is_readable; +use function sprintf; +use PHPUnit\Event\Facade as EventFacade; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapLoader +{ + /** + * @throws BootstrapScriptDoesNotExistException + * @throws BootstrapScriptException + */ + public function handle(Configuration $configuration): void + { + if (!$configuration->hasBootstrap()) { + return; + } + + $this->load($configuration->bootstrap()); + + foreach ($configuration->bootstrapForTestSuite() as $testSuiteName => $bootstrapForTestSuite) { + if ($configuration->includeTestSuites() !== [] && !in_array($testSuiteName, $configuration->includeTestSuites(), true)) { + continue; + } + + if ($configuration->excludeTestSuites() !== [] && in_array($testSuiteName, $configuration->excludeTestSuites(), true)) { + continue; + } + + $this->load($bootstrapForTestSuite); + } + } + + /** + * @param non-empty-string $filename + */ + private function load(string $filename): void + { + if (!is_readable($filename)) { + throw new BootstrapScriptDoesNotExistException($filename); + } + + try { + include_once $filename; + } catch (Throwable $t) { + $message = sprintf( + 'Error in bootstrap script: %s:%s%s%s%s', + $t::class, + PHP_EOL, + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString(), + ); + + while ($t = $t->getPrevious()) { + $message .= sprintf( + '%s%sPrevious error: %s:%s%s%s%s', + PHP_EOL, + PHP_EOL, + $t::class, + PHP_EOL, + $t->getMessage(), + PHP_EOL, + $t->getTraceAsString(), + ); + } + + throw new BootstrapScriptException($message); + } + + EventFacade::emitter()->testRunnerBootstrapFinished($filename); + } +} diff --git a/src/TextUI/Configuration/Builder.php b/src/TextUI/Configuration/Builder.php new file mode 100644 index 00000000000..6f9e81a1558 --- /dev/null +++ b/src/TextUI/Configuration/Builder.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\TextUI\CliArguments\Builder as CliConfigurationBuilder; +use PHPUnit\TextUI\CliArguments\Exception as CliConfigurationException; +use PHPUnit\TextUI\CliArguments\XmlConfigurationFileFinder; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; +use PHPUnit\TextUI\XmlConfiguration\Exception as XmlConfigurationException; +use PHPUnit\TextUI\XmlConfiguration\Loader; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final readonly class Builder +{ + /** + * @param list $argv + * + * @throws ConfigurationCannotBeBuiltException + */ + public function build(array $argv): Configuration + { + try { + $cliConfiguration = (new CliConfigurationBuilder)->fromParameters($argv); + $configurationFile = (new XmlConfigurationFileFinder)->find($cliConfiguration); + $xmlConfiguration = DefaultConfiguration::create(); + + if ($configurationFile !== false) { + $xmlConfiguration = (new Loader)->load($configurationFile); + } + + return Registry::init( + $cliConfiguration, + $xmlConfiguration, + ); + } catch (CliConfigurationException|XmlConfigurationException $e) { + throw new ConfigurationCannotBeBuiltException( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + } +} diff --git a/src/TextUI/Configuration/Cli/Builder.php b/src/TextUI/Configuration/Cli/Builder.php new file mode 100644 index 00000000000..a7caaba7501 --- /dev/null +++ b/src/TextUI/Configuration/Cli/Builder.php @@ -0,0 +1,1417 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use const DIRECTORY_SEPARATOR; +use function assert; +use function basename; +use function explode; +use function getcwd; +use function is_file; +use function is_numeric; +use function sprintf; +use function strtolower; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Util\Filesystem; +use SebastianBergmann\CliParser\Exception as CliParserException; +use SebastianBergmann\CliParser\Parser as CliParser; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Builder +{ + /** + * @var non-empty-list + */ + private const array LONG_OPTIONS = [ + 'all', + 'atleast-version=', + 'bootstrap=', + 'cache-result', + 'do-not-cache-result', + 'cache-directory=', + 'check-version', + 'check-php-configuration', + 'colors==', + 'columns=', + 'configuration=', + 'warm-coverage-cache', + 'coverage-filter=', + 'coverage-clover=', + 'coverage-cobertura=', + 'coverage-crap4j=', + 'coverage-html=', + 'coverage-openclover=', + 'coverage-php=', + 'coverage-text==', + 'only-summary-for-coverage-text', + 'show-uncovered-for-coverage-text', + 'coverage-xml=', + 'exclude-source-from-xml-coverage', + 'path-coverage', + 'disallow-test-output', + 'display-all-issues', + 'display-incomplete', + 'display-skipped', + 'display-deprecations', + 'display-phpunit-deprecations', + 'display-phpunit-notices', + 'display-errors', + 'display-notices', + 'display-warnings', + 'default-time-limit=', + 'enforce-time-limit', + 'exclude-group=', + 'filter=', + 'exclude-filter=', + 'generate-baseline=', + 'use-baseline=', + 'ignore-baseline', + 'generate-configuration', + 'globals-backup', + 'group=', + 'covers=', + 'uses=', + 'requires-php-extension=', + 'help', + 'resolve-dependencies', + 'ignore-dependencies', + 'include-path=', + 'list-groups', + 'list-suites', + 'list-test-files', + 'list-tests', + 'list-tests-xml=', + 'log-junit=', + 'log-otr=', + 'include-git-information', + 'log-teamcity=', + 'migrate-configuration', + 'no-configuration', + 'no-coverage', + 'no-logging', + 'no-extensions', + 'no-output', + 'no-progress', + 'no-results', + 'order-by=', + 'process-isolation', + 'do-not-report-useless-tests', + 'random-order', + 'random-order-seed=', + 'reverse-order', + 'reverse-list', + 'static-backup', + 'stderr', + 'fail-on-all-issues', + 'fail-on-deprecation', + 'fail-on-phpunit-deprecation', + 'fail-on-phpunit-notice', + 'fail-on-phpunit-warning', + 'fail-on-empty-test-suite', + 'fail-on-incomplete', + 'fail-on-notice', + 'fail-on-risky', + 'fail-on-skipped', + 'fail-on-warning', + 'do-not-fail-on-deprecation', + 'do-not-fail-on-phpunit-deprecation', + 'do-not-fail-on-phpunit-notice', + 'do-not-fail-on-phpunit-warning', + 'do-not-fail-on-empty-test-suite', + 'do-not-fail-on-incomplete', + 'do-not-fail-on-notice', + 'do-not-fail-on-risky', + 'do-not-fail-on-skipped', + 'do-not-fail-on-warning', + 'stop-on-defect', + 'stop-on-deprecation==', + 'stop-on-error', + 'stop-on-failure', + 'stop-on-incomplete', + 'stop-on-notice', + 'stop-on-risky', + 'stop-on-skipped', + 'stop-on-warning', + 'strict-coverage', + 'disable-coverage-ignore', + 'strict-global-state', + 'teamcity', + 'testdox', + 'testdox-summary', + 'testdox-html=', + 'testdox-text=', + 'test-suffix=', + 'testsuite=', + 'exclude-testsuite=', + 'log-events-text=', + 'log-events-verbose-text=', + 'version', + 'debug', + 'with-telemetry', + 'extension=', + ]; + + private const string SHORT_OPTIONS = 'd:c:h'; + + /** + * @var array + */ + private array $processed = []; + + /** + * @param list $parameters + * + * @throws Exception + */ + public function fromParameters(array $parameters): Configuration + { + try { + $options = (new CliParser)->parse( + $parameters, + self::SHORT_OPTIONS, + self::LONG_OPTIONS, + ); + } catch (CliParserException $e) { + throw new Exception( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + + $all = null; + $atLeastVersion = null; + $backupGlobals = null; + $backupStaticProperties = null; + $beStrictAboutChangesToGlobalState = null; + $bootstrap = null; + $cacheDirectory = null; + $cacheResult = null; + $checkPhpConfiguration = false; + $checkVersion = false; + $colors = null; + $columns = null; + $configuration = null; + $warmCoverageCache = false; + $coverageFilter = null; + $coverageClover = null; + $coverageCobertura = null; + $coverageCrap4J = null; + $coverageHtml = null; + $coverageOpenClover = null; + $coveragePhp = null; + $coverageText = null; + $coverageTextShowUncoveredFiles = null; + $coverageTextShowOnlySummary = null; + $coverageXml = null; + $excludeSourceFromXmlCoverage = null; + $pathCoverage = null; + $defaultTimeLimit = null; + $disableCodeCoverageIgnore = null; + $disallowTestOutput = null; + $displayAllIssues = null; + $displayIncomplete = null; + $displaySkipped = null; + $displayDeprecations = null; + $displayPhpunitDeprecations = null; + $displayPhpunitNotices = null; + $displayErrors = null; + $displayNotices = null; + $displayWarnings = null; + $enforceTimeLimit = null; + $excludeGroups = null; + $executionOrder = null; + $executionOrderDefects = null; + $failOnAllIssues = null; + $failOnDeprecation = null; + $failOnPhpunitDeprecation = null; + $failOnPhpunitNotice = null; + $failOnPhpunitWarning = null; + $failOnEmptyTestSuite = null; + $failOnIncomplete = null; + $failOnNotice = null; + $failOnRisky = null; + $failOnSkipped = null; + $failOnWarning = null; + $doNotFailOnDeprecation = null; + $doNotFailOnPhpunitDeprecation = null; + $doNotFailOnPhpunitNotice = null; + $doNotFailOnPhpunitWarning = null; + $doNotFailOnEmptyTestSuite = null; + $doNotFailOnIncomplete = null; + $doNotFailOnNotice = null; + $doNotFailOnRisky = null; + $doNotFailOnSkipped = null; + $doNotFailOnWarning = null; + $stopOnDefect = null; + $stopOnDeprecation = null; + $specificDeprecationToStopOn = null; + $stopOnError = null; + $stopOnFailure = null; + $stopOnIncomplete = null; + $stopOnNotice = null; + $stopOnRisky = null; + $stopOnSkipped = null; + $stopOnWarning = null; + $filter = null; + $excludeFilter = null; + $generateBaseline = null; + $useBaseline = null; + $ignoreBaseline = false; + $generateConfiguration = false; + $migrateConfiguration = false; + $groups = null; + $testsCovering = null; + $testsUsing = null; + $testsRequiringPhpExtension = null; + $help = false; + $includePath = null; + $iniSettings = []; + $junitLogfile = null; + $otrLogfile = null; + $includeGitInformation = null; + $listGroups = false; + $listSuites = false; + $listTestFiles = false; + $listTests = false; + $listTestsXml = null; + $noCoverage = null; + $noExtensions = null; + $noOutput = null; + $noProgress = null; + $noResults = null; + $noLogging = null; + $processIsolation = null; + $randomOrderSeed = null; + $reportUselessTests = null; + $resolveDependencies = null; + $reverseList = null; + $stderr = null; + $strictCoverage = null; + $teamcityLogfile = null; + $testdoxHtmlFile = null; + $testdoxTextFile = null; + $testSuffixes = null; + $testSuite = null; + $excludeTestSuite = null; + $useDefaultConfiguration = true; + $version = false; + $logEventsText = null; + $logEventsVerboseText = null; + $printerTeamCity = null; + $printerTestDox = null; + $printerTestDoxSummary = null; + $debug = false; + $withTelemetry = false; + $extensions = []; + + foreach ($options[0] as $option) { + $optionAllowedMultipleTimes = false; + + switch ($option[0]) { + case '--all': + $all = true; + + break; + + case '--colors': + $colors = \PHPUnit\TextUI\Configuration\Configuration::COLOR_AUTO; + + if ($option[1] !== null) { + $colors = $option[1]; + } + + break; + + case '--bootstrap': + $bootstrap = $option[1]; + + break; + + case '--cache-directory': + $cacheDirectory = $option[1]; + + break; + + case '--cache-result': + $cacheResult = true; + + break; + + case '--do-not-cache-result': + $cacheResult = false; + + break; + + case '--columns': + if (is_numeric($option[1])) { + $columns = (int) $option[1]; + } elseif ($option[1] === 'max') { + $columns = 'max'; + } + + break; + + case 'c': + case '--configuration': + $configuration = $option[1]; + + break; + + case '--warm-coverage-cache': + $warmCoverageCache = true; + + break; + + case '--coverage-clover': + $coverageClover = $option[1]; + + break; + + case '--coverage-cobertura': + $coverageCobertura = $option[1]; + + break; + + case '--coverage-crap4j': + $coverageCrap4J = $option[1]; + + break; + + case '--coverage-html': + $coverageHtml = $option[1]; + + break; + + case '--coverage-php': + $coveragePhp = $option[1]; + + break; + + case '--coverage-openclover': + $coverageOpenClover = $option[1]; + + break; + + case '--coverage-text': + if ($option[1] === null) { + $option[1] = 'php://stdout'; + } + + $coverageText = $option[1]; + + break; + + case '--only-summary-for-coverage-text': + $coverageTextShowOnlySummary = true; + + break; + + case '--show-uncovered-for-coverage-text': + $coverageTextShowUncoveredFiles = true; + + break; + + case '--coverage-xml': + $coverageXml = $option[1]; + + break; + + case '--exclude-source-from-xml-coverage': + $excludeSourceFromXmlCoverage = true; + + break; + + case '--path-coverage': + $pathCoverage = true; + + break; + + case 'd': + $tmp = explode('=', $option[1]); + + if (isset($tmp[0])) { + assert($tmp[0] !== ''); + + if (isset($tmp[1])) { + assert($tmp[1] !== ''); + + $iniSettings[$tmp[0]] = $tmp[1]; + } else { + $iniSettings[$tmp[0]] = '1'; + } + } + + $optionAllowedMultipleTimes = true; + + break; + + case 'h': + case '--help': + $help = true; + + break; + + case '--filter': + $filter = $option[1]; + + break; + + case '--exclude-filter': + $excludeFilter = $option[1]; + + break; + + case '--testsuite': + $testSuite = $option[1]; + + break; + + case '--exclude-testsuite': + $excludeTestSuite = $option[1]; + + break; + + case '--generate-baseline': + $generateBaseline = $option[1]; + + if (basename($generateBaseline) === $generateBaseline) { + $generateBaseline = getcwd() . DIRECTORY_SEPARATOR . $generateBaseline; + } + + break; + + case '--use-baseline': + $useBaseline = $option[1]; + + if (basename($useBaseline) === $useBaseline && !is_file($useBaseline)) { + $useBaseline = getcwd() . DIRECTORY_SEPARATOR . $useBaseline; + } + + break; + + case '--ignore-baseline': + $ignoreBaseline = true; + + break; + + case '--generate-configuration': + $generateConfiguration = true; + + break; + + case '--migrate-configuration': + $migrateConfiguration = true; + + break; + + case '--group': + if ($groups === null) { + $groups = []; + } + + $groups[] = $option[1]; + + $optionAllowedMultipleTimes = true; + + break; + + case '--exclude-group': + if ($excludeGroups === null) { + $excludeGroups = []; + } + + $excludeGroups[] = $option[1]; + + $optionAllowedMultipleTimes = true; + + break; + + case '--covers': + if ($testsCovering === null) { + $testsCovering = []; + } + + $testsCovering[] = strtolower($option[1]); + + $optionAllowedMultipleTimes = true; + + break; + + case '--uses': + if ($testsUsing === null) { + $testsUsing = []; + } + + $testsUsing[] = strtolower($option[1]); + + $optionAllowedMultipleTimes = true; + + break; + + case '--requires-php-extension': + if ($testsRequiringPhpExtension === null) { + $testsRequiringPhpExtension = []; + } + + $testsRequiringPhpExtension[] = strtolower($option[1]); + + $optionAllowedMultipleTimes = true; + + break; + + case '--test-suffix': + if ($testSuffixes === null) { + $testSuffixes = []; + } + + $testSuffixes[] = $option[1]; + + $optionAllowedMultipleTimes = true; + + break; + + case '--include-path': + $includePath = $option[1]; + + break; + + case '--list-groups': + $listGroups = true; + + break; + + case '--list-suites': + $listSuites = true; + + break; + + case '--list-test-files': + $listTestFiles = true; + + break; + + case '--list-tests': + $listTests = true; + + break; + + case '--list-tests-xml': + $listTestsXml = $option[1]; + + break; + + case '--log-junit': + $junitLogfile = $option[1]; + + break; + + case '--log-otr': + $otrLogfile = $option[1]; + + break; + + case '--include-git-information': + $includeGitInformation = true; + + break; + + case '--log-teamcity': + $teamcityLogfile = $option[1]; + + break; + + case '--order-by': + foreach (explode(',', $option[1]) as $order) { + switch ($order) { + case 'default': + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; + $resolveDependencies = true; + + break; + + case 'defects': + $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; + + break; + + case 'depends': + $resolveDependencies = true; + + break; + + case 'duration': + $executionOrder = TestSuiteSorter::ORDER_DURATION; + + break; + + case 'no-depends': + $resolveDependencies = false; + + break; + + case 'random': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + + break; + + case 'reverse': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + + break; + + case 'size': + $executionOrder = TestSuiteSorter::ORDER_SIZE; + + break; + + default: + throw new Exception( + sprintf( + 'unrecognized --order-by option: %s', + $order, + ), + ); + } + } + + break; + + case '--process-isolation': + $processIsolation = true; + + break; + + case '--stderr': + $stderr = true; + + break; + + case '--fail-on-all-issues': + $failOnAllIssues = true; + + break; + + case '--fail-on-deprecation': + $this->warnWhenOptionsConflict( + $doNotFailOnDeprecation, + '--fail-on-deprecation', + '--do-not-fail-on-deprecation', + ); + + $failOnDeprecation = true; + + break; + + case '--fail-on-phpunit-deprecation': + $this->warnWhenOptionsConflict( + $doNotFailOnPhpunitDeprecation, + '--fail-on-phpunit-deprecation', + '--do-not-fail-on-phpunit-deprecation', + ); + + $failOnPhpunitDeprecation = true; + + break; + + case '--fail-on-phpunit-notice': + $this->warnWhenOptionsConflict( + $doNotFailOnPhpunitNotice, + '--fail-on-phpunit-notice', + '--do-not-fail-on-phpunit-notice', + ); + + $failOnPhpunitNotice = true; + + break; + + case '--fail-on-phpunit-warning': + $this->warnWhenOptionsConflict( + $doNotFailOnPhpunitWarning, + '--fail-on-phpunit-warning', + '--do-not-fail-on-phpunit-warning', + ); + + $failOnPhpunitWarning = true; + + break; + + case '--fail-on-empty-test-suite': + $this->warnWhenOptionsConflict( + $doNotFailOnEmptyTestSuite, + '--fail-on-empty-test-suite', + '--do-not-fail-on-empty-test-suite', + ); + + $failOnEmptyTestSuite = true; + + break; + + case '--fail-on-incomplete': + $this->warnWhenOptionsConflict( + $doNotFailOnIncomplete, + '--fail-on-incomplete', + '--do-not-fail-on-incomplete', + ); + + $failOnIncomplete = true; + + break; + + case '--fail-on-notice': + $this->warnWhenOptionsConflict( + $doNotFailOnNotice, + '--fail-on-notice', + '--do-not-fail-on-notice', + ); + + $failOnNotice = true; + + break; + + case '--fail-on-risky': + $this->warnWhenOptionsConflict( + $doNotFailOnRisky, + '--fail-on-risky', + '--do-not-fail-on-risky', + ); + + $failOnRisky = true; + + break; + + case '--fail-on-skipped': + $this->warnWhenOptionsConflict( + $doNotFailOnSkipped, + '--fail-on-skipped', + '--do-not-fail-on-skipped', + ); + + $failOnSkipped = true; + + break; + + case '--fail-on-warning': + $this->warnWhenOptionsConflict( + $doNotFailOnWarning, + '--fail-on-warning', + '--do-not-fail-on-warning', + ); + + $failOnWarning = true; + + break; + + case '--do-not-fail-on-deprecation': + $this->warnWhenOptionsConflict( + $failOnDeprecation, + '--do-not-fail-on-deprecation', + '--fail-on-deprecation', + ); + + $doNotFailOnDeprecation = true; + + break; + + case '--do-not-fail-on-phpunit-deprecation': + $this->warnWhenOptionsConflict( + $failOnPhpunitDeprecation, + '--do-not-fail-on-phpunit-deprecation', + '--fail-on-phpunit-deprecation', + ); + + $doNotFailOnPhpunitDeprecation = true; + + break; + + case '--do-not-fail-on-phpunit-notice': + $this->warnWhenOptionsConflict( + $failOnPhpunitNotice, + '--do-not-fail-on-phpunit-notice', + '--fail-on-phpunit-notice', + ); + + $doNotFailOnPhpunitNotice = true; + + break; + + case '--do-not-fail-on-phpunit-warning': + $this->warnWhenOptionsConflict( + $failOnPhpunitWarning, + '--do-not-fail-on-phpunit-warning', + '--fail-on-phpunit-warning', + ); + + $doNotFailOnPhpunitWarning = true; + + break; + + case '--do-not-fail-on-empty-test-suite': + $this->warnWhenOptionsConflict( + $failOnEmptyTestSuite, + '--do-not-fail-on-empty-test-suite', + '--fail-on-empty-test-suite', + ); + + $doNotFailOnEmptyTestSuite = true; + + break; + + case '--do-not-fail-on-incomplete': + $this->warnWhenOptionsConflict( + $failOnIncomplete, + '--do-not-fail-on-incomplete', + '--fail-on-incomplete', + ); + + $doNotFailOnIncomplete = true; + + break; + + case '--do-not-fail-on-notice': + $this->warnWhenOptionsConflict( + $failOnNotice, + '--do-not-fail-on-notice', + '--fail-on-notice', + ); + + $doNotFailOnNotice = true; + + break; + + case '--do-not-fail-on-risky': + $this->warnWhenOptionsConflict( + $failOnRisky, + '--do-not-fail-on-risky', + '--fail-on-risky', + ); + + $doNotFailOnRisky = true; + + break; + + case '--do-not-fail-on-skipped': + $this->warnWhenOptionsConflict( + $failOnSkipped, + '--do-not-fail-on-skipped', + '--fail-on-skipped', + ); + + $doNotFailOnSkipped = true; + + break; + + case '--do-not-fail-on-warning': + $this->warnWhenOptionsConflict( + $failOnWarning, + '--do-not-fail-on-warning', + '--fail-on-warning', + ); + + $doNotFailOnWarning = true; + + break; + + case '--stop-on-defect': + $stopOnDefect = true; + + break; + + case '--stop-on-deprecation': + $stopOnDeprecation = true; + + if ($option[1] !== null) { + $specificDeprecationToStopOn = $option[1]; + } + + break; + + case '--stop-on-error': + $stopOnError = true; + + break; + + case '--stop-on-failure': + $stopOnFailure = true; + + break; + + case '--stop-on-incomplete': + $stopOnIncomplete = true; + + break; + + case '--stop-on-notice': + $stopOnNotice = true; + + break; + + case '--stop-on-risky': + $stopOnRisky = true; + + break; + + case '--stop-on-skipped': + $stopOnSkipped = true; + + break; + + case '--stop-on-warning': + $stopOnWarning = true; + + break; + + case '--teamcity': + $printerTeamCity = true; + + break; + + case '--testdox': + $printerTestDox = true; + + break; + + case '--testdox-summary': + $printerTestDoxSummary = true; + + break; + + case '--testdox-html': + $testdoxHtmlFile = $option[1]; + + break; + + case '--testdox-text': + $testdoxTextFile = $option[1]; + + break; + + case '--no-configuration': + $useDefaultConfiguration = false; + + break; + + case '--no-extensions': + $noExtensions = true; + + break; + + case '--no-coverage': + $noCoverage = true; + + break; + + case '--no-logging': + $noLogging = true; + + break; + + case '--no-output': + $noOutput = true; + + break; + + case '--no-progress': + $noProgress = true; + + break; + + case '--no-results': + $noResults = true; + + break; + + case '--globals-backup': + $backupGlobals = true; + + break; + + case '--static-backup': + $backupStaticProperties = true; + + break; + + case '--atleast-version': + $atLeastVersion = $option[1]; + + break; + + case '--version': + $version = true; + + break; + + case '--do-not-report-useless-tests': + $reportUselessTests = false; + + break; + + case '--strict-coverage': + $strictCoverage = true; + + break; + + case '--disable-coverage-ignore': + $disableCodeCoverageIgnore = true; + + break; + + case '--strict-global-state': + $beStrictAboutChangesToGlobalState = true; + + break; + + case '--disallow-test-output': + $disallowTestOutput = true; + + break; + + case '--display-all-issues': + $displayAllIssues = true; + + break; + + case '--display-incomplete': + $displayIncomplete = true; + + break; + + case '--display-skipped': + $displaySkipped = true; + + break; + + case '--display-deprecations': + $displayDeprecations = true; + + break; + + case '--display-phpunit-deprecations': + $displayPhpunitDeprecations = true; + + break; + + case '--display-phpunit-notices': + $displayPhpunitNotices = true; + + break; + + case '--display-errors': + $displayErrors = true; + + break; + + case '--display-notices': + $displayNotices = true; + + break; + + case '--display-warnings': + $displayWarnings = true; + + break; + + case '--default-time-limit': + $defaultTimeLimit = (int) $option[1]; + + break; + + case '--enforce-time-limit': + $enforceTimeLimit = true; + + break; + + case '--reverse-list': + $reverseList = true; + + break; + + case '--check-php-configuration': + $checkPhpConfiguration = true; + + break; + + case '--check-version': + $checkVersion = true; + + break; + + case '--coverage-filter': + if ($coverageFilter === null) { + $coverageFilter = []; + } + + $coverageFilter[] = $option[1]; + + $optionAllowedMultipleTimes = true; + + break; + + case '--random-order': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + + break; + + case '--random-order-seed': + $randomOrderSeed = (int) $option[1]; + + break; + + case '--resolve-dependencies': + $resolveDependencies = true; + + break; + + case '--ignore-dependencies': + $resolveDependencies = false; + + break; + + case '--reverse-order': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + + break; + + case '--log-events-text': + $logEventsText = Filesystem::resolveStreamOrFile($option[1]); + + if ($logEventsText === false) { + throw new Exception( + sprintf( + 'The path "%s" specified for the --log-events-text option could not be resolved', + $option[1], + ), + ); + } + + break; + + case '--log-events-verbose-text': + $logEventsVerboseText = Filesystem::resolveStreamOrFile($option[1]); + + if ($logEventsVerboseText === false) { + throw new Exception( + sprintf( + 'The path "%s" specified for the --log-events-verbose-text option could not be resolved', + $option[1], + ), + ); + } + + break; + + case '--debug': + $debug = true; + + break; + + case '--with-telemetry': + $withTelemetry = true; + + break; + + case '--extension': + $extensions[] = $option[1]; + + $optionAllowedMultipleTimes = true; + + break; + } + + if (!$optionAllowedMultipleTimes) { + $this->markProcessed($option[0]); + } + } + + if ($iniSettings === []) { + $iniSettings = null; + } + + if ($extensions === []) { + $extensions = null; + } + + return new Configuration( + $options[1], + $all, + $atLeastVersion, + $backupGlobals, + $backupStaticProperties, + $beStrictAboutChangesToGlobalState, + $bootstrap, + $cacheDirectory, + $cacheResult, + $checkPhpConfiguration, + $checkVersion, + $colors, + $columns, + $configuration, + $coverageClover, + $coverageCobertura, + $coverageCrap4J, + $coverageHtml, + $coverageOpenClover, + $coveragePhp, + $coverageText, + $coverageTextShowUncoveredFiles, + $coverageTextShowOnlySummary, + $coverageXml, + $excludeSourceFromXmlCoverage, + $pathCoverage, + $warmCoverageCache, + $defaultTimeLimit, + $disableCodeCoverageIgnore, + $disallowTestOutput, + $enforceTimeLimit, + $excludeGroups, + $executionOrder, + $executionOrderDefects, + $failOnAllIssues, + $failOnDeprecation, + $failOnPhpunitDeprecation, + $failOnPhpunitNotice, + $failOnPhpunitWarning, + $failOnEmptyTestSuite, + $failOnIncomplete, + $failOnNotice, + $failOnRisky, + $failOnSkipped, + $failOnWarning, + $doNotFailOnDeprecation, + $doNotFailOnPhpunitDeprecation, + $doNotFailOnPhpunitNotice, + $doNotFailOnPhpunitWarning, + $doNotFailOnEmptyTestSuite, + $doNotFailOnIncomplete, + $doNotFailOnNotice, + $doNotFailOnRisky, + $doNotFailOnSkipped, + $doNotFailOnWarning, + $stopOnDefect, + $stopOnDeprecation, + $specificDeprecationToStopOn, + $stopOnError, + $stopOnFailure, + $stopOnIncomplete, + $stopOnNotice, + $stopOnRisky, + $stopOnSkipped, + $stopOnWarning, + $filter, + $excludeFilter, + $generateBaseline, + $useBaseline, + $ignoreBaseline, + $generateConfiguration, + $migrateConfiguration, + $groups, + $testsCovering, + $testsUsing, + $testsRequiringPhpExtension, + $help, + $includePath, + $iniSettings, + $junitLogfile, + $otrLogfile, + $includeGitInformation, + $listGroups, + $listSuites, + $listTestFiles, + $listTests, + $listTestsXml, + $noCoverage, + $noExtensions, + $noOutput, + $noProgress, + $noResults, + $noLogging, + $processIsolation, + $randomOrderSeed, + $reportUselessTests, + $resolveDependencies, + $reverseList, + $stderr, + $strictCoverage, + $teamcityLogfile, + $testdoxHtmlFile, + $testdoxTextFile, + $testSuffixes, + $testSuite, + $excludeTestSuite, + $useDefaultConfiguration, + $displayAllIssues, + $displayIncomplete, + $displaySkipped, + $displayDeprecations, + $displayPhpunitDeprecations, + $displayPhpunitNotices, + $displayErrors, + $displayNotices, + $displayWarnings, + $version, + $coverageFilter, + $logEventsText, + $logEventsVerboseText, + $printerTeamCity, + $printerTestDox, + $printerTestDoxSummary, + $debug, + $withTelemetry, + $extensions, + ); + } + + /** + * @param non-empty-string $option + */ + private function markProcessed(string $option): void + { + if (!isset($this->processed[$option])) { + $this->processed[$option] = 1; + + return; + } + + $this->processed[$option]++; + + if ($this->processed[$option] === 2) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Option %s cannot be used more than once', + $option, + ), + ); + } + } + + /** + * @param non-empty-string $option + */ + private function warnWhenOptionsConflict(?bool $current, string $option, string $opposite): void + { + if ($current === null) { + return; + } + + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Options %s and %s cannot be used together', + $option, + $opposite, + ), + ); + } +} diff --git a/src/TextUI/Configuration/Cli/Configuration.php b/src/TextUI/Configuration/Cli/Configuration.php new file mode 100644 index 00000000000..8ccef4ef2ca --- /dev/null +++ b/src/TextUI/Configuration/Cli/Configuration.php @@ -0,0 +1,2629 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Configuration +{ + /** + * @var list + */ + private array $arguments; + private ?bool $all; + private ?string $atLeastVersion; + private ?bool $backupGlobals; + private ?bool $backupStaticProperties; + private ?bool $beStrictAboutChangesToGlobalState; + private ?string $bootstrap; + private ?string $cacheDirectory; + private ?bool $cacheResult; + private bool $checkPhpConfiguration; + private bool $checkVersion; + private ?string $colors; + private null|int|string $columns; + private ?string $configurationFile; + + /** + * @var ?non-empty-list + */ + private ?array $coverageFilter; + private ?string $coverageClover; + private ?string $coverageCobertura; + private ?string $coverageCrap4J; + private ?string $coverageHtml; + private ?string $coverageOpenClover; + private ?string $coveragePhp; + private ?string $coverageText; + private ?bool $coverageTextShowUncoveredFiles; + private ?bool $coverageTextShowOnlySummary; + private ?string $coverageXml; + private ?bool $excludeSourceFromXmlCoverage; + private ?bool $pathCoverage; + private bool $warmCoverageCache; + private ?int $defaultTimeLimit; + private ?bool $disableCodeCoverageIgnore; + private ?bool $disallowTestOutput; + private ?bool $enforceTimeLimit; + + /** + * @var ?non-empty-list + */ + private ?array $excludeGroups; + private ?int $executionOrder; + private ?int $executionOrderDefects; + private ?bool $failOnAllIssues; + private ?bool $failOnDeprecation; + private ?bool $failOnPhpunitDeprecation; + private ?bool $failOnPhpunitNotice; + private ?bool $failOnPhpunitWarning; + private ?bool $failOnEmptyTestSuite; + private ?bool $failOnIncomplete; + private ?bool $failOnNotice; + private ?bool $failOnRisky; + private ?bool $failOnSkipped; + private ?bool $failOnWarning; + private ?bool $doNotFailOnDeprecation; + private ?bool $doNotFailOnPhpunitDeprecation; + private ?bool $doNotFailOnPhpunitNotice; + private ?bool $doNotFailOnPhpunitWarning; + private ?bool $doNotFailOnEmptyTestSuite; + private ?bool $doNotFailOnIncomplete; + private ?bool $doNotFailOnNotice; + private ?bool $doNotFailOnRisky; + private ?bool $doNotFailOnSkipped; + private ?bool $doNotFailOnWarning; + private ?bool $stopOnDefect; + private ?bool $stopOnDeprecation; + private ?string $specificDeprecationToStopOn; + private ?bool $stopOnError; + private ?bool $stopOnFailure; + private ?bool $stopOnIncomplete; + private ?bool $stopOnNotice; + private ?bool $stopOnRisky; + private ?bool $stopOnSkipped; + private ?bool $stopOnWarning; + private ?string $filter; + private ?string $excludeFilter; + private ?string $generateBaseline; + private ?string $useBaseline; + private bool $ignoreBaseline; + private bool $generateConfiguration; + private bool $migrateConfiguration; + + /** + * @var ?non-empty-list + */ + private ?array $groups; + + /** + * @var ?non-empty-list + */ + private ?array $testsCovering; + + /** + * @var ?non-empty-list + */ + private ?array $testsUsing; + + /** + * @var ?non-empty-list + */ + private ?array $testsRequiringPhpExtension; + private bool $help; + private ?string $includePath; + + /** + * @var ?non-empty-array + */ + private ?array $iniSettings; + private ?string $junitLogfile; + private ?string $otrLogfile; + private ?bool $includeGitInformationInOtrLogfile; + private bool $listGroups; + private bool $listSuites; + private bool $listTestFiles; + private bool $listTests; + private ?string $listTestsXml; + private ?bool $noCoverage; + private ?bool $noExtensions; + private ?bool $noOutput; + private ?bool $noProgress; + private ?bool $noResults; + private ?bool $noLogging; + private ?bool $processIsolation; + private ?int $randomOrderSeed; + private ?bool $reportUselessTests; + private ?bool $resolveDependencies; + private ?bool $reverseList; + private ?bool $stderr; + private ?bool $strictCoverage; + private ?string $teamcityLogfile; + private ?bool $teamCityPrinter; + private ?string $testdoxHtmlFile; + private ?string $testdoxTextFile; + private ?bool $testdoxPrinter; + private ?bool $testdoxPrinterSummary; + + /** + * @var ?non-empty-list + */ + private ?array $testSuffixes; + private ?string $testSuite; + private ?string $excludeTestSuite; + private bool $useDefaultConfiguration; + private ?bool $displayDetailsOnAllIssues; + private ?bool $displayDetailsOnIncompleteTests; + private ?bool $displayDetailsOnSkippedTests; + private ?bool $displayDetailsOnTestsThatTriggerDeprecations; + private ?bool $displayDetailsOnPhpunitDeprecations; + private ?bool $displayDetailsOnPhpunitNotices; + private ?bool $displayDetailsOnTestsThatTriggerErrors; + private ?bool $displayDetailsOnTestsThatTriggerNotices; + private ?bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $version; + private ?string $logEventsText; + private ?string $logEventsVerboseText; + private bool $debug; + private bool $withTelemetry; + + /** + * @var ?non-empty-list + */ + private ?array $extensions; + + /** + * @param list $arguments + * @param ?non-empty-list $excludeGroups + * @param ?non-empty-list $groups + * @param ?non-empty-list $testsCovering + * @param ?non-empty-list $testsUsing + * @param ?non-empty-list $testsRequiringPhpExtension + * @param ?non-empty-array $iniSettings + * @param ?non-empty-list $testSuffixes + * @param ?non-empty-list $coverageFilter + * @param ?non-empty-list $extensions + */ + public function __construct(array $arguments, ?bool $all, ?string $atLeastVersion, ?bool $backupGlobals, ?bool $backupStaticProperties, ?bool $beStrictAboutChangesToGlobalState, ?string $bootstrap, ?string $cacheDirectory, ?bool $cacheResult, bool $checkPhpConfiguration, bool $checkVersion, ?string $colors, null|int|string $columns, ?string $configurationFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4J, ?string $coverageHtml, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, ?bool $coverageTextShowUncoveredFiles, ?bool $coverageTextShowOnlySummary, ?string $coverageXml, ?bool $coverageXmlIncludeSource, ?bool $pathCoverage, bool $warmCoverageCache, ?int $defaultTimeLimit, ?bool $disableCodeCoverageIgnore, ?bool $disallowTestOutput, ?bool $enforceTimeLimit, ?array $excludeGroups, ?int $executionOrder, ?int $executionOrderDefects, ?bool $failOnAllIssues, ?bool $failOnDeprecation, ?bool $failOnPhpunitDeprecation, ?bool $failOnPhpunitNotice, ?bool $failOnPhpunitWarning, ?bool $failOnEmptyTestSuite, ?bool $failOnIncomplete, ?bool $failOnNotice, ?bool $failOnRisky, ?bool $failOnSkipped, ?bool $failOnWarning, ?bool $doNotFailOnDeprecation, ?bool $doNotFailOnPhpunitDeprecation, ?bool $doNotFailOnPhpunitNotice, ?bool $doNotFailOnPhpunitWarning, ?bool $doNotFailOnEmptyTestSuite, ?bool $doNotFailOnIncomplete, ?bool $doNotFailOnNotice, ?bool $doNotFailOnRisky, ?bool $doNotFailOnSkipped, ?bool $doNotFailOnWarning, ?bool $stopOnDefect, ?bool $stopOnDeprecation, ?string $specificDeprecationToStopOn, ?bool $stopOnError, ?bool $stopOnFailure, ?bool $stopOnIncomplete, ?bool $stopOnNotice, ?bool $stopOnRisky, ?bool $stopOnSkipped, ?bool $stopOnWarning, ?string $filter, ?string $excludeFilter, ?string $generateBaseline, ?string $useBaseline, bool $ignoreBaseline, bool $generateConfiguration, bool $migrateConfiguration, ?array $groups, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, bool $help, ?string $includePath, ?array $iniSettings, ?string $junitLogfile, ?string $otrLogfile, ?bool $includeGitInformation, bool $listGroups, bool $listSuites, bool $listTestFiles, bool $listTests, ?string $listTestsXml, ?bool $noCoverage, ?bool $noExtensions, ?bool $noOutput, ?bool $noProgress, ?bool $noResults, ?bool $noLogging, ?bool $processIsolation, ?int $randomOrderSeed, ?bool $reportUselessTests, ?bool $resolveDependencies, ?bool $reverseList, ?bool $stderr, ?bool $strictCoverage, ?string $teamcityLogfile, ?string $testdoxHtmlFile, ?string $testdoxTextFile, ?array $testSuffixes, ?string $testSuite, ?string $excludeTestSuite, bool $useDefaultConfiguration, ?bool $displayDetailsOnAllIssues, ?bool $displayDetailsOnIncompleteTests, ?bool $displayDetailsOnSkippedTests, ?bool $displayDetailsOnTestsThatTriggerDeprecations, ?bool $displayDetailsOnPhpunitDeprecations, ?bool $displayDetailsOnPhpunitNotices, ?bool $displayDetailsOnTestsThatTriggerErrors, ?bool $displayDetailsOnTestsThatTriggerNotices, ?bool $displayDetailsOnTestsThatTriggerWarnings, bool $version, ?array $coverageFilter, ?string $logEventsText, ?string $logEventsVerboseText, ?bool $printerTeamCity, ?bool $testdoxPrinter, ?bool $testdoxPrinterSummary, bool $debug, bool $withTelemetry, ?array $extensions) + { + $this->arguments = $arguments; + $this->all = $all; + $this->atLeastVersion = $atLeastVersion; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->bootstrap = $bootstrap; + $this->cacheDirectory = $cacheDirectory; + $this->cacheResult = $cacheResult; + $this->checkPhpConfiguration = $checkPhpConfiguration; + $this->checkVersion = $checkVersion; + $this->colors = $colors; + $this->columns = $columns; + $this->configurationFile = $configurationFile; + $this->coverageFilter = $coverageFilter; + $this->coverageClover = $coverageClover; + $this->coverageCobertura = $coverageCobertura; + $this->coverageCrap4J = $coverageCrap4J; + $this->coverageHtml = $coverageHtml; + $this->coverageOpenClover = $coverageOpenClover; + $this->coveragePhp = $coveragePhp; + $this->coverageText = $coverageText; + $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; + $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; + $this->coverageXml = $coverageXml; + $this->excludeSourceFromXmlCoverage = $coverageXmlIncludeSource; + $this->pathCoverage = $pathCoverage; + $this->warmCoverageCache = $warmCoverageCache; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->disallowTestOutput = $disallowTestOutput; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->excludeGroups = $excludeGroups; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->doNotFailOnDeprecation = $doNotFailOnDeprecation; + $this->doNotFailOnPhpunitDeprecation = $doNotFailOnPhpunitDeprecation; + $this->doNotFailOnPhpunitNotice = $doNotFailOnPhpunitNotice; + $this->doNotFailOnPhpunitWarning = $doNotFailOnPhpunitWarning; + $this->doNotFailOnEmptyTestSuite = $doNotFailOnEmptyTestSuite; + $this->doNotFailOnIncomplete = $doNotFailOnIncomplete; + $this->doNotFailOnNotice = $doNotFailOnNotice; + $this->doNotFailOnRisky = $doNotFailOnRisky; + $this->doNotFailOnSkipped = $doNotFailOnSkipped; + $this->doNotFailOnWarning = $doNotFailOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->specificDeprecationToStopOn = $specificDeprecationToStopOn; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->filter = $filter; + $this->excludeFilter = $excludeFilter; + $this->generateBaseline = $generateBaseline; + $this->useBaseline = $useBaseline; + $this->ignoreBaseline = $ignoreBaseline; + $this->generateConfiguration = $generateConfiguration; + $this->migrateConfiguration = $migrateConfiguration; + $this->groups = $groups; + $this->testsCovering = $testsCovering; + $this->testsUsing = $testsUsing; + $this->testsRequiringPhpExtension = $testsRequiringPhpExtension; + $this->help = $help; + $this->includePath = $includePath; + $this->iniSettings = $iniSettings; + $this->junitLogfile = $junitLogfile; + $this->otrLogfile = $otrLogfile; + $this->includeGitInformationInOtrLogfile = $includeGitInformation; + $this->listGroups = $listGroups; + $this->listSuites = $listSuites; + $this->listTestFiles = $listTestFiles; + $this->listTests = $listTests; + $this->listTestsXml = $listTestsXml; + $this->noCoverage = $noCoverage; + $this->noExtensions = $noExtensions; + $this->noOutput = $noOutput; + $this->noProgress = $noProgress; + $this->noResults = $noResults; + $this->noLogging = $noLogging; + $this->processIsolation = $processIsolation; + $this->randomOrderSeed = $randomOrderSeed; + $this->reportUselessTests = $reportUselessTests; + $this->resolveDependencies = $resolveDependencies; + $this->reverseList = $reverseList; + $this->stderr = $stderr; + $this->strictCoverage = $strictCoverage; + $this->teamcityLogfile = $teamcityLogfile; + $this->testdoxHtmlFile = $testdoxHtmlFile; + $this->testdoxTextFile = $testdoxTextFile; + $this->testSuffixes = $testSuffixes; + $this->testSuite = $testSuite; + $this->excludeTestSuite = $excludeTestSuite; + $this->useDefaultConfiguration = $useDefaultConfiguration; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->version = $version; + $this->logEventsText = $logEventsText; + $this->logEventsVerboseText = $logEventsVerboseText; + $this->teamCityPrinter = $printerTeamCity; + $this->testdoxPrinter = $testdoxPrinter; + $this->testdoxPrinterSummary = $testdoxPrinterSummary; + $this->debug = $debug; + $this->withTelemetry = $withTelemetry; + $this->extensions = $extensions; + } + + /** + * @return list + */ + public function arguments(): array + { + return $this->arguments; + } + + /** + * @phpstan-assert-if-true !null $this->all + */ + public function hasAll(): bool + { + return $this->all !== null; + } + + /** + * @throws Exception + */ + public function all(): bool + { + if (!$this->hasAll()) { + throw new Exception; + } + + return $this->all; + } + + /** + * @phpstan-assert-if-true !null $this->atLeastVersion + */ + public function hasAtLeastVersion(): bool + { + return $this->atLeastVersion !== null; + } + + /** + * @throws Exception + */ + public function atLeastVersion(): string + { + if (!$this->hasAtLeastVersion()) { + throw new Exception; + } + + return $this->atLeastVersion; + } + + /** + * @phpstan-assert-if-true !null $this->backupGlobals + */ + public function hasBackupGlobals(): bool + { + return $this->backupGlobals !== null; + } + + /** + * @throws Exception + */ + public function backupGlobals(): bool + { + if (!$this->hasBackupGlobals()) { + throw new Exception; + } + + return $this->backupGlobals; + } + + /** + * @phpstan-assert-if-true !null $this->backupStaticProperties + */ + public function hasBackupStaticProperties(): bool + { + return $this->backupStaticProperties !== null; + } + + /** + * @throws Exception + */ + public function backupStaticProperties(): bool + { + if (!$this->hasBackupStaticProperties()) { + throw new Exception; + } + + return $this->backupStaticProperties; + } + + /** + * @phpstan-assert-if-true !null $this->beStrictAboutChangesToGlobalState + */ + public function hasBeStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState !== null; + } + + /** + * @throws Exception + */ + public function beStrictAboutChangesToGlobalState(): bool + { + if (!$this->hasBeStrictAboutChangesToGlobalState()) { + throw new Exception; + } + + return $this->beStrictAboutChangesToGlobalState; + } + + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + + /** + * @throws Exception + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new Exception; + } + + return $this->bootstrap; + } + + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + + /** + * @throws Exception + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new Exception; + } + + return $this->cacheDirectory; + } + + /** + * @phpstan-assert-if-true !null $this->cacheResult + */ + public function hasCacheResult(): bool + { + return $this->cacheResult !== null; + } + + /** + * @throws Exception + */ + public function cacheResult(): bool + { + if (!$this->hasCacheResult()) { + throw new Exception; + } + + return $this->cacheResult; + } + + public function checkPhpConfiguration(): bool + { + return $this->checkPhpConfiguration; + } + + public function checkVersion(): bool + { + return $this->checkVersion; + } + + /** + * @phpstan-assert-if-true !null $this->colors + */ + public function hasColors(): bool + { + return $this->colors !== null; + } + + /** + * @throws Exception + */ + public function colors(): string + { + if (!$this->hasColors()) { + throw new Exception; + } + + return $this->colors; + } + + /** + * @phpstan-assert-if-true !null $this->columns + */ + public function hasColumns(): bool + { + return $this->columns !== null; + } + + /** + * @throws Exception + */ + public function columns(): int|string + { + if (!$this->hasColumns()) { + throw new Exception; + } + + return $this->columns; + } + + /** + * @phpstan-assert-if-true !null $this->configurationFile + */ + public function hasConfigurationFile(): bool + { + return $this->configurationFile !== null; + } + + /** + * @throws Exception + */ + public function configurationFile(): string + { + if (!$this->hasConfigurationFile()) { + throw new Exception; + } + + return $this->configurationFile; + } + + /** + * @phpstan-assert-if-true !null $this->coverageFilter + */ + public function hasCoverageFilter(): bool + { + return $this->coverageFilter !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function coverageFilter(): array + { + if (!$this->hasCoverageFilter()) { + throw new Exception; + } + + return $this->coverageFilter; + } + + /** + * @phpstan-assert-if-true !null $this->coverageClover + */ + public function hasCoverageClover(): bool + { + return $this->coverageClover !== null; + } + + /** + * @throws Exception + */ + public function coverageClover(): string + { + if (!$this->hasCoverageClover()) { + throw new Exception; + } + + return $this->coverageClover; + } + + /** + * @phpstan-assert-if-true !null $this->coverageCobertura + */ + public function hasCoverageCobertura(): bool + { + return $this->coverageCobertura !== null; + } + + /** + * @throws Exception + */ + public function coverageCobertura(): string + { + if (!$this->hasCoverageCobertura()) { + throw new Exception; + } + + return $this->coverageCobertura; + } + + /** + * @phpstan-assert-if-true !null $this->coverageCrap4J + */ + public function hasCoverageCrap4J(): bool + { + return $this->coverageCrap4J !== null; + } + + /** + * @throws Exception + */ + public function coverageCrap4J(): string + { + if (!$this->hasCoverageCrap4J()) { + throw new Exception; + } + + return $this->coverageCrap4J; + } + + /** + * @phpstan-assert-if-true !null $this->coverageHtml + */ + public function hasCoverageHtml(): bool + { + return $this->coverageHtml !== null; + } + + /** + * @throws Exception + */ + public function coverageHtml(): string + { + if (!$this->hasCoverageHtml()) { + throw new Exception; + } + + return $this->coverageHtml; + } + + /** + * @phpstan-assert-if-true !null $this->coverageOpenClover + */ + public function hasCoverageOpenClover(): bool + { + return $this->coverageOpenClover !== null; + } + + /** + * @throws Exception + */ + public function coverageOpenClover(): string + { + if (!$this->hasCoverageOpenClover()) { + throw new Exception; + } + + return $this->coverageOpenClover; + } + + /** + * @phpstan-assert-if-true !null $this->coveragePhp + */ + public function hasCoveragePhp(): bool + { + return $this->coveragePhp !== null; + } + + /** + * @throws Exception + */ + public function coveragePhp(): string + { + if (!$this->hasCoveragePhp()) { + throw new Exception; + } + + return $this->coveragePhp; + } + + /** + * @phpstan-assert-if-true !null $this->coverageText + */ + public function hasCoverageText(): bool + { + return $this->coverageText !== null; + } + + /** + * @throws Exception + */ + public function coverageText(): string + { + if (!$this->hasCoverageText()) { + throw new Exception; + } + + return $this->coverageText; + } + + /** + * @phpstan-assert-if-true !null $this->coverageTextShowUncoveredFiles + */ + public function hasCoverageTextShowUncoveredFiles(): bool + { + return $this->coverageTextShowUncoveredFiles !== null; + } + + /** + * @throws Exception + */ + public function coverageTextShowUncoveredFiles(): bool + { + if (!$this->hasCoverageTextShowUncoveredFiles()) { + throw new Exception; + } + + return $this->coverageTextShowUncoveredFiles; + } + + /** + * @phpstan-assert-if-true !null $this->coverageTextShowOnlySummary + */ + public function hasCoverageTextShowOnlySummary(): bool + { + return $this->coverageTextShowOnlySummary !== null; + } + + /** + * @throws Exception + */ + public function coverageTextShowOnlySummary(): bool + { + if (!$this->hasCoverageTextShowOnlySummary()) { + throw new Exception; + } + + return $this->coverageTextShowOnlySummary; + } + + /** + * @phpstan-assert-if-true !null $this->coverageXml + */ + public function hasCoverageXml(): bool + { + return $this->coverageXml !== null; + } + + /** + * @throws Exception + */ + public function coverageXml(): string + { + if (!$this->hasCoverageXml()) { + throw new Exception; + } + + return $this->coverageXml; + } + + /** + * @phpstan-assert-if-true !null $this->excludeSourceFromXmlCoverage + */ + public function hasExcludeSourceFromXmlCoverage(): bool + { + return $this->excludeSourceFromXmlCoverage !== null; + } + + /** + * @throws Exception + */ + public function excludeSourceFromXmlCoverage(): bool + { + if (!$this->hasExcludeSourceFromXmlCoverage()) { + throw new Exception; + } + + return $this->excludeSourceFromXmlCoverage; + } + + /** + * @phpstan-assert-if-true !null $this->pathCoverage + */ + public function hasPathCoverage(): bool + { + return $this->pathCoverage !== null; + } + + /** + * @throws Exception + */ + public function pathCoverage(): bool + { + if (!$this->hasPathCoverage()) { + throw new Exception; + } + + return $this->pathCoverage; + } + + public function warmCoverageCache(): bool + { + return $this->warmCoverageCache; + } + + /** + * @phpstan-assert-if-true !null $this->defaultTimeLimit + */ + public function hasDefaultTimeLimit(): bool + { + return $this->defaultTimeLimit !== null; + } + + /** + * @throws Exception + */ + public function defaultTimeLimit(): int + { + if (!$this->hasDefaultTimeLimit()) { + throw new Exception; + } + + return $this->defaultTimeLimit; + } + + /** + * @phpstan-assert-if-true !null $this->disableCodeCoverageIgnore + */ + public function hasDisableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore !== null; + } + + /** + * @throws Exception + */ + public function disableCodeCoverageIgnore(): bool + { + if (!$this->hasDisableCodeCoverageIgnore()) { + throw new Exception; + } + + return $this->disableCodeCoverageIgnore; + } + + /** + * @phpstan-assert-if-true !null $this->disallowTestOutput + */ + public function hasDisallowTestOutput(): bool + { + return $this->disallowTestOutput !== null; + } + + /** + * @throws Exception + */ + public function disallowTestOutput(): bool + { + if (!$this->hasDisallowTestOutput()) { + throw new Exception; + } + + return $this->disallowTestOutput; + } + + /** + * @phpstan-assert-if-true !null $this->enforceTimeLimit + */ + public function hasEnforceTimeLimit(): bool + { + return $this->enforceTimeLimit !== null; + } + + /** + * @throws Exception + */ + public function enforceTimeLimit(): bool + { + if (!$this->hasEnforceTimeLimit()) { + throw new Exception; + } + + return $this->enforceTimeLimit; + } + + /** + * @phpstan-assert-if-true !null $this->excludeGroups + */ + public function hasExcludeGroups(): bool + { + return $this->excludeGroups !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function excludeGroups(): array + { + if (!$this->hasExcludeGroups()) { + throw new Exception; + } + + return $this->excludeGroups; + } + + /** + * @phpstan-assert-if-true !null $this->executionOrder + */ + public function hasExecutionOrder(): bool + { + return $this->executionOrder !== null; + } + + /** + * @throws Exception + */ + public function executionOrder(): int + { + if (!$this->hasExecutionOrder()) { + throw new Exception; + } + + return $this->executionOrder; + } + + /** + * @phpstan-assert-if-true !null $this->executionOrderDefects + */ + public function hasExecutionOrderDefects(): bool + { + return $this->executionOrderDefects !== null; + } + + /** + * @throws Exception + */ + public function executionOrderDefects(): int + { + if (!$this->hasExecutionOrderDefects()) { + throw new Exception; + } + + return $this->executionOrderDefects; + } + + /** + * @phpstan-assert-if-true !null $this->failOnAllIssues + */ + public function hasFailOnAllIssues(): bool + { + return $this->failOnAllIssues !== null; + } + + /** + * @throws Exception + */ + public function failOnAllIssues(): bool + { + if (!$this->hasFailOnAllIssues()) { + throw new Exception; + } + + return $this->failOnAllIssues; + } + + /** + * @phpstan-assert-if-true !null $this->failOnDeprecation + */ + public function hasFailOnDeprecation(): bool + { + return $this->failOnDeprecation !== null; + } + + /** + * @throws Exception + */ + public function failOnDeprecation(): bool + { + if (!$this->hasFailOnDeprecation()) { + throw new Exception; + } + + return $this->failOnDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitDeprecation + */ + public function hasFailOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation !== null; + } + + /** + * @throws Exception + */ + public function failOnPhpunitDeprecation(): bool + { + if (!$this->hasFailOnPhpunitDeprecation()) { + throw new Exception; + } + + return $this->failOnPhpunitDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitNotice + */ + public function hasFailOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice !== null; + } + + /** + * @throws Exception + */ + public function failOnPhpunitNotice(): bool + { + if (!$this->hasFailOnPhpunitNotice()) { + throw new Exception; + } + + return $this->failOnPhpunitNotice; + } + + /** + * @phpstan-assert-if-true !null $this->failOnPhpunitWarning + */ + public function hasFailOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning !== null; + } + + /** + * @throws Exception + */ + public function failOnPhpunitWarning(): bool + { + if (!$this->hasFailOnPhpunitWarning()) { + throw new Exception; + } + + return $this->failOnPhpunitWarning; + } + + /** + * @phpstan-assert-if-true !null $this->failOnEmptyTestSuite + */ + public function hasFailOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite !== null; + } + + /** + * @throws Exception + */ + public function failOnEmptyTestSuite(): bool + { + if (!$this->hasFailOnEmptyTestSuite()) { + throw new Exception; + } + + return $this->failOnEmptyTestSuite; + } + + /** + * @phpstan-assert-if-true !null $this->failOnIncomplete + */ + public function hasFailOnIncomplete(): bool + { + return $this->failOnIncomplete !== null; + } + + /** + * @throws Exception + */ + public function failOnIncomplete(): bool + { + if (!$this->hasFailOnIncomplete()) { + throw new Exception; + } + + return $this->failOnIncomplete; + } + + /** + * @phpstan-assert-if-true !null $this->failOnNotice + */ + public function hasFailOnNotice(): bool + { + return $this->failOnNotice !== null; + } + + /** + * @throws Exception + */ + public function failOnNotice(): bool + { + if (!$this->hasFailOnNotice()) { + throw new Exception; + } + + return $this->failOnNotice; + } + + /** + * @phpstan-assert-if-true !null $this->failOnRisky + */ + public function hasFailOnRisky(): bool + { + return $this->failOnRisky !== null; + } + + /** + * @throws Exception + */ + public function failOnRisky(): bool + { + if (!$this->hasFailOnRisky()) { + throw new Exception; + } + + return $this->failOnRisky; + } + + /** + * @phpstan-assert-if-true !null $this->failOnSkipped + */ + public function hasFailOnSkipped(): bool + { + return $this->failOnSkipped !== null; + } + + /** + * @throws Exception + */ + public function failOnSkipped(): bool + { + if (!$this->hasFailOnSkipped()) { + throw new Exception; + } + + return $this->failOnSkipped; + } + + /** + * @phpstan-assert-if-true !null $this->failOnWarning + */ + public function hasFailOnWarning(): bool + { + return $this->failOnWarning !== null; + } + + /** + * @throws Exception + */ + public function failOnWarning(): bool + { + if (!$this->hasFailOnWarning()) { + throw new Exception; + } + + return $this->failOnWarning; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnDeprecation + */ + public function hasDoNotFailOnDeprecation(): bool + { + return $this->doNotFailOnDeprecation !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnDeprecation(): bool + { + if (!$this->hasDoNotFailOnDeprecation()) { + throw new Exception; + } + + return $this->doNotFailOnDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitDeprecation + */ + public function hasDoNotFailOnPhpunitDeprecation(): bool + { + return $this->doNotFailOnPhpunitDeprecation !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnPhpunitDeprecation(): bool + { + if (!$this->hasDoNotFailOnPhpunitDeprecation()) { + throw new Exception; + } + + return $this->doNotFailOnPhpunitDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitNotice + */ + public function hasDoNotFailOnPhpunitNotice(): bool + { + return $this->doNotFailOnPhpunitNotice !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnPhpunitNotice(): bool + { + if (!$this->hasDoNotFailOnPhpunitNotice()) { + throw new Exception; + } + + return $this->doNotFailOnPhpunitNotice; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnPhpunitWarning + */ + public function hasDoNotFailOnPhpunitWarning(): bool + { + return $this->doNotFailOnPhpunitWarning !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnPhpunitWarning(): bool + { + if (!$this->hasDoNotFailOnPhpunitWarning()) { + throw new Exception; + } + + return $this->doNotFailOnPhpunitWarning; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnEmptyTestSuite + */ + public function hasDoNotFailOnEmptyTestSuite(): bool + { + return $this->doNotFailOnEmptyTestSuite !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnEmptyTestSuite(): bool + { + if (!$this->hasDoNotFailOnEmptyTestSuite()) { + throw new Exception; + } + + return $this->doNotFailOnEmptyTestSuite; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnIncomplete + */ + public function hasDoNotFailOnIncomplete(): bool + { + return $this->doNotFailOnIncomplete !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnIncomplete(): bool + { + if (!$this->hasDoNotFailOnIncomplete()) { + throw new Exception; + } + + return $this->doNotFailOnIncomplete; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnNotice + */ + public function hasDoNotFailOnNotice(): bool + { + return $this->doNotFailOnNotice !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnNotice(): bool + { + if (!$this->hasDoNotFailOnNotice()) { + throw new Exception; + } + + return $this->doNotFailOnNotice; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnRisky + */ + public function hasDoNotFailOnRisky(): bool + { + return $this->doNotFailOnRisky !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnRisky(): bool + { + if (!$this->hasDoNotFailOnRisky()) { + throw new Exception; + } + + return $this->doNotFailOnRisky; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnSkipped + */ + public function hasDoNotFailOnSkipped(): bool + { + return $this->doNotFailOnSkipped !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnSkipped(): bool + { + if (!$this->hasDoNotFailOnSkipped()) { + throw new Exception; + } + + return $this->doNotFailOnSkipped; + } + + /** + * @phpstan-assert-if-true !null $this->doNotFailOnWarning + */ + public function hasDoNotFailOnWarning(): bool + { + return $this->doNotFailOnWarning !== null; + } + + /** + * @throws Exception + */ + public function doNotFailOnWarning(): bool + { + if (!$this->hasDoNotFailOnWarning()) { + throw new Exception; + } + + return $this->doNotFailOnWarning; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnDefect + */ + public function hasStopOnDefect(): bool + { + return $this->stopOnDefect !== null; + } + + /** + * @throws Exception + */ + public function stopOnDefect(): bool + { + if (!$this->hasStopOnDefect()) { + throw new Exception; + } + + return $this->stopOnDefect; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnDeprecation + */ + public function hasStopOnDeprecation(): bool + { + return $this->stopOnDeprecation !== null; + } + + /** + * @throws Exception + */ + public function stopOnDeprecation(): bool + { + if (!$this->hasStopOnDeprecation()) { + throw new Exception; + } + + return $this->stopOnDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->specificDeprecationToStopOn + */ + public function hasSpecificDeprecationToStopOn(): bool + { + return $this->specificDeprecationToStopOn !== null; + } + + /** + * @throws Exception + */ + public function specificDeprecationToStopOn(): string + { + if (!$this->hasSpecificDeprecationToStopOn()) { + throw new Exception; + } + + return $this->specificDeprecationToStopOn; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnError + */ + public function hasStopOnError(): bool + { + return $this->stopOnError !== null; + } + + /** + * @throws Exception + */ + public function stopOnError(): bool + { + if (!$this->hasStopOnError()) { + throw new Exception; + } + + return $this->stopOnError; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnFailure + */ + public function hasStopOnFailure(): bool + { + return $this->stopOnFailure !== null; + } + + /** + * @throws Exception + */ + public function stopOnFailure(): bool + { + if (!$this->hasStopOnFailure()) { + throw new Exception; + } + + return $this->stopOnFailure; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnIncomplete + */ + public function hasStopOnIncomplete(): bool + { + return $this->stopOnIncomplete !== null; + } + + /** + * @throws Exception + */ + public function stopOnIncomplete(): bool + { + if (!$this->hasStopOnIncomplete()) { + throw new Exception; + } + + return $this->stopOnIncomplete; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnNotice + */ + public function hasStopOnNotice(): bool + { + return $this->stopOnNotice !== null; + } + + /** + * @throws Exception + */ + public function stopOnNotice(): bool + { + if (!$this->hasStopOnNotice()) { + throw new Exception; + } + + return $this->stopOnNotice; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnRisky + */ + public function hasStopOnRisky(): bool + { + return $this->stopOnRisky !== null; + } + + /** + * @throws Exception + */ + public function stopOnRisky(): bool + { + if (!$this->hasStopOnRisky()) { + throw new Exception; + } + + return $this->stopOnRisky; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnSkipped + */ + public function hasStopOnSkipped(): bool + { + return $this->stopOnSkipped !== null; + } + + /** + * @throws Exception + */ + public function stopOnSkipped(): bool + { + if (!$this->hasStopOnSkipped()) { + throw new Exception; + } + + return $this->stopOnSkipped; + } + + /** + * @phpstan-assert-if-true !null $this->stopOnWarning + */ + public function hasStopOnWarning(): bool + { + return $this->stopOnWarning !== null; + } + + /** + * @throws Exception + */ + public function stopOnWarning(): bool + { + if (!$this->hasStopOnWarning()) { + throw new Exception; + } + + return $this->stopOnWarning; + } + + /** + * @phpstan-assert-if-true !null $this->excludeFilter + */ + public function hasExcludeFilter(): bool + { + return $this->excludeFilter !== null; + } + + /** + * @throws Exception + */ + public function excludeFilter(): string + { + if (!$this->hasExcludeFilter()) { + throw new Exception; + } + + return $this->excludeFilter; + } + + /** + * @phpstan-assert-if-true !null $this->filter + */ + public function hasFilter(): bool + { + return $this->filter !== null; + } + + /** + * @throws Exception + */ + public function filter(): string + { + if (!$this->hasFilter()) { + throw new Exception; + } + + return $this->filter; + } + + /** + * @phpstan-assert-if-true !null $this->generateBaseline + */ + public function hasGenerateBaseline(): bool + { + return $this->generateBaseline !== null; + } + + /** + * @throws Exception + */ + public function generateBaseline(): string + { + if (!$this->hasGenerateBaseline()) { + throw new Exception; + } + + return $this->generateBaseline; + } + + /** + * @phpstan-assert-if-true !null $this->useBaseline + */ + public function hasUseBaseline(): bool + { + return $this->useBaseline !== null; + } + + /** + * @throws Exception + */ + public function useBaseline(): string + { + if (!$this->hasUseBaseline()) { + throw new Exception; + } + + return $this->useBaseline; + } + + public function ignoreBaseline(): bool + { + return $this->ignoreBaseline; + } + + public function generateConfiguration(): bool + { + return $this->generateConfiguration; + } + + public function migrateConfiguration(): bool + { + return $this->migrateConfiguration; + } + + /** + * @phpstan-assert-if-true !null $this->groups + */ + public function hasGroups(): bool + { + return $this->groups !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function groups(): array + { + if (!$this->hasGroups()) { + throw new Exception; + } + + return $this->groups; + } + + /** + * @phpstan-assert-if-true !null $this->testsCovering + */ + public function hasTestsCovering(): bool + { + return $this->testsCovering !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsCovering(): array + { + if (!$this->hasTestsCovering()) { + throw new Exception; + } + + return $this->testsCovering; + } + + /** + * @phpstan-assert-if-true !null $this->testsUsing + */ + public function hasTestsUsing(): bool + { + return $this->testsUsing !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsUsing(): array + { + if (!$this->hasTestsUsing()) { + throw new Exception; + } + + return $this->testsUsing; + } + + /** + * @phpstan-assert-if-true !null $this->testsRequiringPhpExtension + */ + public function hasTestsRequiringPhpExtension(): bool + { + return $this->testsRequiringPhpExtension !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testsRequiringPhpExtension(): array + { + if (!$this->hasTestsRequiringPhpExtension()) { + throw new Exception; + } + + return $this->testsRequiringPhpExtension; + } + + public function help(): bool + { + return $this->help; + } + + /** + * @phpstan-assert-if-true !null $this->includePath + */ + public function hasIncludePath(): bool + { + return $this->includePath !== null; + } + + /** + * @throws Exception + */ + public function includePath(): string + { + if (!$this->hasIncludePath()) { + throw new Exception; + } + + return $this->includePath; + } + + /** + * @phpstan-assert-if-true !null $this->iniSettings + */ + public function hasIniSettings(): bool + { + return $this->iniSettings !== null; + } + + /** + * @throws Exception + * + * @return non-empty-array + */ + public function iniSettings(): array + { + if (!$this->hasIniSettings()) { + throw new Exception; + } + + return $this->iniSettings; + } + + /** + * @phpstan-assert-if-true !null $this->junitLogfile + */ + public function hasJunitLogfile(): bool + { + return $this->junitLogfile !== null; + } + + /** + * @throws Exception + */ + public function junitLogfile(): string + { + if (!$this->hasJunitLogfile()) { + throw new Exception; + } + + return $this->junitLogfile; + } + + /** + * @phpstan-assert-if-true !null $this->otrLogfile + */ + public function hasOtrLogfile(): bool + { + return $this->otrLogfile !== null; + } + + /** + * @throws Exception + */ + public function otrLogfile(): string + { + if (!$this->hasOtrLogfile()) { + throw new Exception; + } + + return $this->otrLogfile; + } + + /** + * @phpstan-assert-if-true !null $this->includeGitInformationInOtrLogfile + */ + public function hasIncludeGitInformationInOtrLogfile(): bool + { + return $this->includeGitInformationInOtrLogfile !== null; + } + + /** + * @throws Exception + */ + public function includeGitInformationInOtrLogfile(): bool + { + if (!$this->hasIncludeGitInformationInOtrLogfile()) { + throw new Exception; + } + + return $this->includeGitInformationInOtrLogfile; + } + + public function listGroups(): bool + { + return $this->listGroups; + } + + public function listSuites(): bool + { + return $this->listSuites; + } + + public function listTestFiles(): bool + { + return $this->listTestFiles; + } + + public function listTests(): bool + { + return $this->listTests; + } + + /** + * @phpstan-assert-if-true !null $this->listTestsXml + */ + public function hasListTestsXml(): bool + { + return $this->listTestsXml !== null; + } + + /** + * @throws Exception + */ + public function listTestsXml(): string + { + if (!$this->hasListTestsXml()) { + throw new Exception; + } + + return $this->listTestsXml; + } + + /** + * @phpstan-assert-if-true !null $this->noCoverage + */ + public function hasNoCoverage(): bool + { + return $this->noCoverage !== null; + } + + /** + * @throws Exception + */ + public function noCoverage(): bool + { + if (!$this->hasNoCoverage()) { + throw new Exception; + } + + return $this->noCoverage; + } + + /** + * @phpstan-assert-if-true !null $this->noExtensions + */ + public function hasNoExtensions(): bool + { + return $this->noExtensions !== null; + } + + /** + * @throws Exception + */ + public function noExtensions(): bool + { + if (!$this->hasNoExtensions()) { + throw new Exception; + } + + return $this->noExtensions; + } + + /** + * @phpstan-assert-if-true !null $this->noOutput + */ + public function hasNoOutput(): bool + { + return $this->noOutput !== null; + } + + /** + * @throws Exception + */ + public function noOutput(): bool + { + if ($this->noOutput === null) { + throw new Exception; + } + + return $this->noOutput; + } + + /** + * @phpstan-assert-if-true !null $this->noProgress + */ + public function hasNoProgress(): bool + { + return $this->noProgress !== null; + } + + /** + * @throws Exception + */ + public function noProgress(): bool + { + if ($this->noProgress === null) { + throw new Exception; + } + + return $this->noProgress; + } + + /** + * @phpstan-assert-if-true !null $this->noResults + */ + public function hasNoResults(): bool + { + return $this->noResults !== null; + } + + /** + * @throws Exception + */ + public function noResults(): bool + { + if ($this->noResults === null) { + throw new Exception; + } + + return $this->noResults; + } + + /** + * @phpstan-assert-if-true !null $this->noLogging + */ + public function hasNoLogging(): bool + { + return $this->noLogging !== null; + } + + /** + * @throws Exception + */ + public function noLogging(): bool + { + if (!$this->hasNoLogging()) { + throw new Exception; + } + + return $this->noLogging; + } + + /** + * @phpstan-assert-if-true !null $this->processIsolation + */ + public function hasProcessIsolation(): bool + { + return $this->processIsolation !== null; + } + + /** + * @throws Exception + */ + public function processIsolation(): bool + { + if (!$this->hasProcessIsolation()) { + throw new Exception; + } + + return $this->processIsolation; + } + + /** + * @phpstan-assert-if-true !null $this->randomOrderSeed + */ + public function hasRandomOrderSeed(): bool + { + return $this->randomOrderSeed !== null; + } + + /** + * @throws Exception + */ + public function randomOrderSeed(): int + { + if (!$this->hasRandomOrderSeed()) { + throw new Exception; + } + + return $this->randomOrderSeed; + } + + /** + * @phpstan-assert-if-true !null $this->reportUselessTests + */ + public function hasReportUselessTests(): bool + { + return $this->reportUselessTests !== null; + } + + /** + * @throws Exception + */ + public function reportUselessTests(): bool + { + if (!$this->hasReportUselessTests()) { + throw new Exception; + } + + return $this->reportUselessTests; + } + + /** + * @phpstan-assert-if-true !null $this->resolveDependencies + */ + public function hasResolveDependencies(): bool + { + return $this->resolveDependencies !== null; + } + + /** + * @throws Exception + */ + public function resolveDependencies(): bool + { + if (!$this->hasResolveDependencies()) { + throw new Exception; + } + + return $this->resolveDependencies; + } + + /** + * @phpstan-assert-if-true !null $this->reverseList + */ + public function hasReverseList(): bool + { + return $this->reverseList !== null; + } + + /** + * @throws Exception + */ + public function reverseList(): bool + { + if (!$this->hasReverseList()) { + throw new Exception; + } + + return $this->reverseList; + } + + /** + * @phpstan-assert-if-true !null $this->stderr + */ + public function hasStderr(): bool + { + return $this->stderr !== null; + } + + /** + * @throws Exception + */ + public function stderr(): bool + { + if (!$this->hasStderr()) { + throw new Exception; + } + + return $this->stderr; + } + + /** + * @phpstan-assert-if-true !null $this->strictCoverage + */ + public function hasStrictCoverage(): bool + { + return $this->strictCoverage !== null; + } + + /** + * @throws Exception + */ + public function strictCoverage(): bool + { + if (!$this->hasStrictCoverage()) { + throw new Exception; + } + + return $this->strictCoverage; + } + + /** + * @phpstan-assert-if-true !null $this->teamcityLogfile + */ + public function hasTeamcityLogfile(): bool + { + return $this->teamcityLogfile !== null; + } + + /** + * @throws Exception + */ + public function teamcityLogfile(): string + { + if (!$this->hasTeamcityLogfile()) { + throw new Exception; + } + + return $this->teamcityLogfile; + } + + /** + * @phpstan-assert-if-true !null $this->teamCityPrinter + */ + public function hasTeamCityPrinter(): bool + { + return $this->teamCityPrinter !== null; + } + + /** + * @throws Exception + */ + public function teamCityPrinter(): bool + { + if (!$this->hasTeamCityPrinter()) { + throw new Exception; + } + + return $this->teamCityPrinter; + } + + /** + * @phpstan-assert-if-true !null $this->testdoxHtmlFile + */ + public function hasTestdoxHtmlFile(): bool + { + return $this->testdoxHtmlFile !== null; + } + + /** + * @throws Exception + */ + public function testdoxHtmlFile(): string + { + if (!$this->hasTestdoxHtmlFile()) { + throw new Exception; + } + + return $this->testdoxHtmlFile; + } + + /** + * @phpstan-assert-if-true !null $this->testdoxTextFile + */ + public function hasTestdoxTextFile(): bool + { + return $this->testdoxTextFile !== null; + } + + /** + * @throws Exception + */ + public function testdoxTextFile(): string + { + if (!$this->hasTestdoxTextFile()) { + throw new Exception; + } + + return $this->testdoxTextFile; + } + + /** + * @phpstan-assert-if-true !null $this->testdoxPrinter + */ + public function hasTestDoxPrinter(): bool + { + return $this->testdoxPrinter !== null; + } + + /** + * @throws Exception + */ + public function testdoxPrinter(): bool + { + if (!$this->hasTestDoxPrinter()) { + throw new Exception; + } + + return $this->testdoxPrinter; + } + + /** + * @phpstan-assert-if-true !null $this->testdoxPrinterSummary + */ + public function hasTestDoxPrinterSummary(): bool + { + return $this->testdoxPrinterSummary !== null; + } + + /** + * @throws Exception + */ + public function testdoxPrinterSummary(): bool + { + if (!$this->hasTestDoxPrinterSummary()) { + throw new Exception; + } + + return $this->testdoxPrinterSummary; + } + + /** + * @phpstan-assert-if-true !null $this->testSuffixes + */ + public function hasTestSuffixes(): bool + { + return $this->testSuffixes !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function testSuffixes(): array + { + if (!$this->hasTestSuffixes()) { + throw new Exception; + } + + return $this->testSuffixes; + } + + /** + * @phpstan-assert-if-true !null $this->testSuite + */ + public function hasTestSuite(): bool + { + return $this->testSuite !== null; + } + + /** + * @throws Exception + */ + public function testSuite(): string + { + if (!$this->hasTestSuite()) { + throw new Exception; + } + + return $this->testSuite; + } + + /** + * @phpstan-assert-if-true !null $this->excludeTestSuite + */ + public function hasExcludedTestSuite(): bool + { + return $this->excludeTestSuite !== null; + } + + /** + * @throws Exception + */ + public function excludedTestSuite(): string + { + if (!$this->hasExcludedTestSuite()) { + throw new Exception; + } + + return $this->excludeTestSuite; + } + + public function useDefaultConfiguration(): bool + { + return $this->useDefaultConfiguration; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnAllIssues + */ + public function hasDisplayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnAllIssues(): bool + { + if (!$this->hasDisplayDetailsOnAllIssues()) { + throw new Exception; + } + + return $this->displayDetailsOnAllIssues; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnIncompleteTests + */ + public function hasDisplayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnIncompleteTests(): bool + { + if (!$this->hasDisplayDetailsOnIncompleteTests()) { + throw new Exception; + } + + return $this->displayDetailsOnIncompleteTests; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnSkippedTests + */ + public function hasDisplayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnSkippedTests(): bool + { + if (!$this->hasDisplayDetailsOnSkippedTests()) { + throw new Exception; + } + + return $this->displayDetailsOnSkippedTests; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerDeprecations + */ + public function hasDisplayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { + throw new Exception; + } + + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnPhpunitDeprecations + */ + public function hasDisplayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnPhpunitDeprecations(): bool + { + if (!$this->hasDisplayDetailsOnPhpunitDeprecations()) { + throw new Exception; + } + + return $this->displayDetailsOnPhpunitDeprecations; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnPhpunitNotices + */ + public function hasDisplayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnPhpunitNotices(): bool + { + if (!$this->hasDisplayDetailsOnPhpunitNotices()) { + throw new Exception; + } + + return $this->displayDetailsOnPhpunitNotices; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerErrors + */ + public function hasDisplayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerErrors()) { + throw new Exception; + } + + return $this->displayDetailsOnTestsThatTriggerErrors; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerNotices + */ + public function hasDisplayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerNotices()) { + throw new Exception; + } + + return $this->displayDetailsOnTestsThatTriggerNotices; + } + + /** + * @phpstan-assert-if-true !null $this->displayDetailsOnTestsThatTriggerWarnings + */ + public function hasDisplayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings !== null; + } + + /** + * @throws Exception + */ + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + if (!$this->hasDisplayDetailsOnTestsThatTriggerWarnings()) { + throw new Exception; + } + + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + + public function version(): bool + { + return $this->version; + } + + /** + * @phpstan-assert-if-true !null $this->logEventsText + */ + public function hasLogEventsText(): bool + { + return $this->logEventsText !== null; + } + + /** + * @throws Exception + */ + public function logEventsText(): string + { + if (!$this->hasLogEventsText()) { + throw new Exception; + } + + return $this->logEventsText; + } + + /** + * @phpstan-assert-if-true !null $this->logEventsVerboseText + */ + public function hasLogEventsVerboseText(): bool + { + return $this->logEventsVerboseText !== null; + } + + /** + * @throws Exception + */ + public function logEventsVerboseText(): string + { + if (!$this->hasLogEventsVerboseText()) { + throw new Exception; + } + + return $this->logEventsVerboseText; + } + + public function debug(): bool + { + return $this->debug; + } + + public function withTelemetry(): bool + { + return $this->withTelemetry; + } + + /** + * @phpstan-assert-if-true !null $this->extensions + */ + public function hasExtensions(): bool + { + return $this->extensions !== null; + } + + /** + * @throws Exception + * + * @return non-empty-list + */ + public function extensions(): array + { + if (!$this->hasExtensions()) { + throw new Exception; + } + + return $this->extensions; + } +} diff --git a/src/TextUI/Configuration/Cli/Exception.php b/src/TextUI/Configuration/Cli/Exception.php new file mode 100644 index 00000000000..0d9a5a00e6e --- /dev/null +++ b/src/TextUI/Configuration/Cli/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends RuntimeException implements \PHPUnit\Exception +{ +} diff --git a/src/TextUI/Configuration/Cli/XmlConfigurationFileFinder.php b/src/TextUI/Configuration/Cli/XmlConfigurationFileFinder.php new file mode 100644 index 00000000000..5357ef63d0a --- /dev/null +++ b/src/TextUI/Configuration/Cli/XmlConfigurationFileFinder.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use function getcwd; +use function is_dir; +use function is_file; +use function realpath; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class XmlConfigurationFileFinder +{ + public function find(Configuration $configuration): false|string + { + $useDefaultConfiguration = $configuration->useDefaultConfiguration(); + + if ($configuration->hasConfigurationFile()) { + if (is_dir($configuration->configurationFile())) { + $candidate = $this->configurationFileInDirectory($configuration->configurationFile()); + + if ($candidate !== false) { + return $candidate; + } + + return false; + } + + return $configuration->configurationFile(); + } + + if ($useDefaultConfiguration) { + $directory = getcwd(); + + if ($directory !== false) { + $candidate = $this->configurationFileInDirectory($directory); + + if ($candidate !== false) { + return $candidate; + } + } + } + + return false; + } + + private function configurationFileInDirectory(string $directory): false|string + { + $candidates = [ + $directory . '/phpunit.xml', + $directory . '/phpunit.dist.xml', + $directory . '/phpunit.xml.dist', + ]; + + foreach ($candidates as $candidate) { + if (is_file($candidate)) { + return realpath($candidate); + } + } + + return false; + } +} diff --git a/src/TextUI/Configuration/CodeCoverageFilterRegistry.php b/src/TextUI/Configuration/CodeCoverageFilterRegistry.php new file mode 100644 index 00000000000..7051d2840d8 --- /dev/null +++ b/src/TextUI/Configuration/CodeCoverageFilterRegistry.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function array_keys; +use function assert; +use SebastianBergmann\CodeCoverage\Filter; + +/** + * CLI options and XML configuration are static within a single PHPUnit process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverageFilterRegistry +{ + private static ?self $instance = null; + private ?Filter $filter = null; + private bool $configured = false; + + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self; + } + + return self::$instance; + } + + /** + * @codeCoverageIgnore + */ + public function get(): Filter + { + assert($this->filter !== null); + + return $this->filter; + } + + /** + * @codeCoverageIgnore + */ + public function init(Configuration $configuration, bool $force = false): void + { + if (!$configuration->hasCoverageReport() && !$force) { + return; + } + + if ($this->configured && !$force) { + return; + } + + $this->filter = new Filter; + + if ($configuration->source()->notEmpty()) { + $this->filter->includeFiles(array_keys((new SourceMapper)->map($configuration->source()))); + + $this->configured = true; + } + } + + /** + * @codeCoverageIgnore + */ + public function configured(): bool + { + return $this->configured; + } +} diff --git a/src/TextUI/Configuration/Configuration.php b/src/TextUI/Configuration/Configuration.php new file mode 100644 index 00000000000..b673966d7fc --- /dev/null +++ b/src/TextUI/Configuration/Configuration.php @@ -0,0 +1,1536 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function explode; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Configuration +{ + public const string COLOR_NEVER = 'never'; + public const string COLOR_AUTO = 'auto'; + public const string COLOR_ALWAYS = 'always'; + public const string COLOR_DEFAULT = self::COLOR_NEVER; + + /** + * @var list + */ + private array $cliArguments; + private ?string $configurationFile; + private ?string $bootstrap; + + /** + * @var array + */ + private array $bootstrapForTestSuite; + private bool $cacheResult; + private ?string $cacheDirectory; + private ?string $coverageCacheDirectory; + private Source $source; + private bool $pathCoverage; + private ?string $coverageClover; + private ?string $coverageCobertura; + private ?string $coverageCrap4j; + private int $coverageCrap4jThreshold; + private ?string $coverageHtml; + private int $coverageHtmlLowUpperBound; + private int $coverageHtmlHighLowerBound; + private string $coverageHtmlColorSuccessLow; + private string $coverageHtmlColorSuccessMedium; + private string $coverageHtmlColorSuccessHigh; + private string $coverageHtmlColorWarning; + private string $coverageHtmlColorDanger; + private ?string $coverageHtmlCustomCssFile; + private ?string $coverageOpenClover; + private ?string $coveragePhp; + private ?string $coverageText; + private bool $coverageTextShowUncoveredFiles; + private bool $coverageTextShowOnlySummary; + private ?string $coverageXml; + private bool $coverageXmlIncludeSource; + private string $testResultCacheFile; + private bool $ignoreDeprecatedCodeUnitsFromCodeCoverage; + private bool $disableCodeCoverageIgnore; + private bool $failOnAllIssues; + private bool $failOnDeprecation; + private bool $failOnPhpunitDeprecation; + private bool $failOnPhpunitNotice; + private bool $failOnPhpunitWarning; + private bool $failOnEmptyTestSuite; + private bool $failOnIncomplete; + private bool $failOnNotice; + private bool $failOnRisky; + private bool $failOnSkipped; + private bool $failOnWarning; + private bool $doNotFailOnDeprecation; + private bool $doNotFailOnPhpunitDeprecation; + private bool $doNotFailOnPhpunitNotice; + private bool $doNotFailOnPhpunitWarning; + private bool $doNotFailOnEmptyTestSuite; + private bool $doNotFailOnIncomplete; + private bool $doNotFailOnNotice; + private bool $doNotFailOnRisky; + private bool $doNotFailOnSkipped; + private bool $doNotFailOnWarning; + private bool $stopOnDefect; + private bool $stopOnDeprecation; + private ?string $specificDeprecationToStopOn; + private bool $stopOnError; + private bool $stopOnFailure; + private bool $stopOnIncomplete; + private bool $stopOnNotice; + private bool $stopOnRisky; + private bool $stopOnSkipped; + private bool $stopOnWarning; + private bool $outputToStandardErrorStream; + private int $columns; + private bool $noExtensions; + + /** + * @var ?non-empty-string + */ + private ?string $pharExtensionDirectory; + + /** + * @var list}> + */ + private array $extensionBootstrappers; + private bool $backupGlobals; + private bool $backupStaticProperties; + private bool $beStrictAboutChangesToGlobalState; + private bool $colors; + private bool $processIsolation; + private bool $enforceTimeLimit; + private int $defaultTimeLimit; + private int $timeoutForSmallTests; + private int $timeoutForMediumTests; + private int $timeoutForLargeTests; + private bool $reportUselessTests; + private bool $strictCoverage; + private bool $disallowTestOutput; + private bool $displayDetailsOnAllIssues; + private bool $displayDetailsOnIncompleteTests; + private bool $displayDetailsOnSkippedTests; + private bool $displayDetailsOnTestsThatTriggerDeprecations; + private bool $displayDetailsOnPhpunitDeprecations; + private bool $displayDetailsOnPhpunitNotices; + private bool $displayDetailsOnTestsThatTriggerErrors; + private bool $displayDetailsOnTestsThatTriggerNotices; + private bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $reverseDefectList; + private bool $requireCoverageMetadata; + private bool $noProgress; + private bool $noResults; + private bool $noOutput; + private int $executionOrder; + private int $executionOrderDefects; + private bool $resolveDependencies; + private ?string $logfileTeamcity; + private ?string $logfileJunit; + private ?string $logfileOtr; + private bool $includeGitInformationInOtrLogfile; + private ?string $logfileTestdoxHtml; + private ?string $logfileTestdoxText; + private ?string $logEventsText; + private ?string $logEventsVerboseText; + + /** + * @var ?non-empty-list + */ + private ?array $testsCovering; + + /** + * @var ?non-empty-list + */ + private ?array $testsUsing; + + /** + * @var ?non-empty-list + */ + private ?array $testsRequiringPhpExtension; + private bool $teamCityOutput; + private bool $testDoxOutput; + private bool $testDoxOutputSummary; + private ?string $filter; + private ?string $excludeFilter; + + /** + * @var list + */ + private array $groups; + + /** + * @var list + */ + private array $excludeGroups; + private int $randomOrderSeed; + private bool $includeUncoveredFiles; + private TestSuiteCollection $testSuite; + private string $includeTestSuite; + private string $excludeTestSuite; + private ?string $defaultTestSuite; + private bool $ignoreTestSelectionInXmlConfiguration; + + /** + * @var non-empty-list + */ + private array $testSuffixes; + private Php $php; + private bool $controlGarbageCollector; + private int $numberOfTestsBeforeGarbageCollection; + + /** + * @var null|non-empty-string + */ + private ?string $generateBaseline; + private bool $debug; + private bool $withTelemetry; + + /** + * @var non-negative-int + */ + private int $shortenArraysForExportThreshold; + + /** + * @param list $cliArguments + * @param array $bootstrapForTestSuite + * @param ?non-empty-string $pharExtensionDirectory + * @param list}> $extensionBootstrappers + * @param ?non-empty-list $testsCovering + * @param ?non-empty-list $testsUsing + * @param ?non-empty-list $testsRequiringPhpExtension + * @param list $groups + * @param list $excludeGroups + * @param non-empty-list $testSuffixes + * @param null|non-empty-string $generateBaseline + * @param non-negative-int $shortenArraysForExportThreshold + */ + public function __construct(array $cliArguments, ?string $configurationFile, ?string $bootstrap, array $bootstrapForTestSuite, bool $cacheResult, ?string $cacheDirectory, ?string $coverageCacheDirectory, Source $source, string $testResultCacheFile, ?string $coverageClover, ?string $coverageCobertura, ?string $coverageCrap4j, int $coverageCrap4jThreshold, ?string $coverageHtml, int $coverageHtmlLowUpperBound, int $coverageHtmlHighLowerBound, string $coverageHtmlColorSuccessLow, string $coverageHtmlColorSuccessMedium, string $coverageHtmlColorSuccessHigh, string $coverageHtmlColorWarning, string $coverageHtmlColorDanger, ?string $coverageHtmlCustomCssFile, ?string $coverageOpenClover, ?string $coveragePhp, ?string $coverageText, bool $coverageTextShowUncoveredFiles, bool $coverageTextShowOnlySummary, ?string $coverageXml, bool $coverageXmlIncludeSource, bool $pathCoverage, bool $ignoreDeprecatedCodeUnitsFromCodeCoverage, bool $disableCodeCoverageIgnore, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $doNotFailOnDeprecation, bool $doNotFailOnPhpunitDeprecation, bool $doNotFailOnPhpunitNotice, bool $doNotFailOnPhpunitWarning, bool $doNotFailOnEmptyTestSuite, bool $doNotFailOnIncomplete, bool $doNotFailOnNotice, bool $doNotFailOnRisky, bool $doNotFailOnSkipped, bool $doNotFailOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, ?string $specificDeprecationToStopOn, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, bool $outputToStandardErrorStream, int $columns, bool $noExtensions, ?string $pharExtensionDirectory, array $extensionBootstrappers, bool $backupGlobals, bool $backupStaticProperties, bool $beStrictAboutChangesToGlobalState, bool $colors, bool $processIsolation, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, bool $reportUselessTests, bool $strictCoverage, bool $disallowTestOutput, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, bool $noProgress, bool $noResults, bool $noOutput, int $executionOrder, int $executionOrderDefects, bool $resolveDependencies, ?string $logfileTeamcity, ?string $logfileJunit, ?string $logfileOtr, bool $includeGitInformationInOtrLogfile, ?string $logfileTestdoxHtml, ?string $logfileTestdoxText, ?string $logEventsText, ?string $logEventsVerboseText, bool $teamCityOutput, bool $testDoxOutput, bool $testDoxOutputSummary, ?array $testsCovering, ?array $testsUsing, ?array $testsRequiringPhpExtension, ?string $filter, ?string $excludeFilter, array $groups, array $excludeGroups, int $randomOrderSeed, bool $includeUncoveredFiles, TestSuiteCollection $testSuite, string $includeTestSuite, string $excludeTestSuite, ?string $defaultTestSuite, bool $ignoreTestSelectionInXmlConfiguration, array $testSuffixes, Php $php, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, ?string $generateBaseline, bool $debug, bool $withTelemetry, int $shortenArraysForExportThreshold) + { + $this->cliArguments = $cliArguments; + $this->configurationFile = $configurationFile; + $this->bootstrap = $bootstrap; + $this->bootstrapForTestSuite = $bootstrapForTestSuite; + $this->cacheResult = $cacheResult; + $this->cacheDirectory = $cacheDirectory; + $this->coverageCacheDirectory = $coverageCacheDirectory; + $this->source = $source; + $this->testResultCacheFile = $testResultCacheFile; + $this->coverageClover = $coverageClover; + $this->coverageCobertura = $coverageCobertura; + $this->coverageCrap4j = $coverageCrap4j; + $this->coverageCrap4jThreshold = $coverageCrap4jThreshold; + $this->coverageHtml = $coverageHtml; + $this->coverageHtmlLowUpperBound = $coverageHtmlLowUpperBound; + $this->coverageHtmlHighLowerBound = $coverageHtmlHighLowerBound; + $this->coverageHtmlColorSuccessLow = $coverageHtmlColorSuccessLow; + $this->coverageHtmlColorSuccessMedium = $coverageHtmlColorSuccessMedium; + $this->coverageHtmlColorSuccessHigh = $coverageHtmlColorSuccessHigh; + $this->coverageHtmlColorWarning = $coverageHtmlColorWarning; + $this->coverageHtmlColorDanger = $coverageHtmlColorDanger; + $this->coverageHtmlCustomCssFile = $coverageHtmlCustomCssFile; + $this->coverageOpenClover = $coverageOpenClover; + $this->coveragePhp = $coveragePhp; + $this->coverageText = $coverageText; + $this->coverageTextShowUncoveredFiles = $coverageTextShowUncoveredFiles; + $this->coverageTextShowOnlySummary = $coverageTextShowOnlySummary; + $this->coverageXml = $coverageXml; + $this->coverageXmlIncludeSource = $coverageXmlIncludeSource; + $this->pathCoverage = $pathCoverage; + $this->ignoreDeprecatedCodeUnitsFromCodeCoverage = $ignoreDeprecatedCodeUnitsFromCodeCoverage; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->doNotFailOnDeprecation = $doNotFailOnDeprecation; + $this->doNotFailOnPhpunitDeprecation = $doNotFailOnPhpunitDeprecation; + $this->doNotFailOnPhpunitNotice = $doNotFailOnPhpunitNotice; + $this->doNotFailOnPhpunitWarning = $doNotFailOnPhpunitWarning; + $this->doNotFailOnEmptyTestSuite = $doNotFailOnEmptyTestSuite; + $this->doNotFailOnIncomplete = $doNotFailOnIncomplete; + $this->doNotFailOnNotice = $doNotFailOnNotice; + $this->doNotFailOnRisky = $doNotFailOnRisky; + $this->doNotFailOnSkipped = $doNotFailOnSkipped; + $this->doNotFailOnWarning = $doNotFailOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->specificDeprecationToStopOn = $specificDeprecationToStopOn; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->outputToStandardErrorStream = $outputToStandardErrorStream; + $this->columns = $columns; + $this->noExtensions = $noExtensions; + $this->pharExtensionDirectory = $pharExtensionDirectory; + $this->extensionBootstrappers = $extensionBootstrappers; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->colors = $colors; + $this->processIsolation = $processIsolation; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->timeoutForSmallTests = $timeoutForSmallTests; + $this->timeoutForMediumTests = $timeoutForMediumTests; + $this->timeoutForLargeTests = $timeoutForLargeTests; + $this->reportUselessTests = $reportUselessTests; + $this->strictCoverage = $strictCoverage; + $this->disallowTestOutput = $disallowTestOutput; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->reverseDefectList = $reverseDefectList; + $this->requireCoverageMetadata = $requireCoverageMetadata; + $this->noProgress = $noProgress; + $this->noResults = $noResults; + $this->noOutput = $noOutput; + $this->executionOrder = $executionOrder; + $this->executionOrderDefects = $executionOrderDefects; + $this->resolveDependencies = $resolveDependencies; + $this->logfileTeamcity = $logfileTeamcity; + $this->logfileJunit = $logfileJunit; + $this->logfileOtr = $logfileOtr; + $this->includeGitInformationInOtrLogfile = $includeGitInformationInOtrLogfile; + $this->logfileTestdoxHtml = $logfileTestdoxHtml; + $this->logfileTestdoxText = $logfileTestdoxText; + $this->logEventsText = $logEventsText; + $this->logEventsVerboseText = $logEventsVerboseText; + $this->teamCityOutput = $teamCityOutput; + $this->testDoxOutput = $testDoxOutput; + $this->testDoxOutputSummary = $testDoxOutputSummary; + $this->testsCovering = $testsCovering; + $this->testsUsing = $testsUsing; + $this->testsRequiringPhpExtension = $testsRequiringPhpExtension; + $this->filter = $filter; + $this->excludeFilter = $excludeFilter; + $this->groups = $groups; + $this->excludeGroups = $excludeGroups; + $this->randomOrderSeed = $randomOrderSeed; + $this->includeUncoveredFiles = $includeUncoveredFiles; + $this->testSuite = $testSuite; + $this->includeTestSuite = $includeTestSuite; + $this->excludeTestSuite = $excludeTestSuite; + $this->defaultTestSuite = $defaultTestSuite; + $this->ignoreTestSelectionInXmlConfiguration = $ignoreTestSelectionInXmlConfiguration; + $this->testSuffixes = $testSuffixes; + $this->php = $php; + $this->controlGarbageCollector = $controlGarbageCollector; + $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; + $this->generateBaseline = $generateBaseline; + $this->debug = $debug; + $this->withTelemetry = $withTelemetry; + $this->shortenArraysForExportThreshold = $shortenArraysForExportThreshold; + } + + /** + * @phpstan-assert-if-true !empty $this->cliArguments + */ + public function hasCliArguments(): bool + { + return $this->cliArguments !== []; + } + + /** + * @return list + */ + public function cliArguments(): array + { + return $this->cliArguments; + } + + /** + * @phpstan-assert-if-true !null $this->configurationFile + */ + public function hasConfigurationFile(): bool + { + return $this->configurationFile !== null; + } + + /** + * @throws NoConfigurationFileException + */ + public function configurationFile(): string + { + if (!$this->hasConfigurationFile()) { + throw new NoConfigurationFileException; + } + + return $this->configurationFile; + } + + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + + /** + * @throws NoBootstrapException + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new NoBootstrapException; + } + + return $this->bootstrap; + } + + /** + * @return array + */ + public function bootstrapForTestSuite(): array + { + return $this->bootstrapForTestSuite; + } + + public function cacheResult(): bool + { + return $this->cacheResult; + } + + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + + /** + * @throws NoCacheDirectoryException + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new NoCacheDirectoryException; + } + + return $this->cacheDirectory; + } + + /** + * @phpstan-assert-if-true !null $this->coverageCacheDirectory + */ + public function hasCoverageCacheDirectory(): bool + { + return $this->coverageCacheDirectory !== null; + } + + /** + * @throws NoCoverageCacheDirectoryException + */ + public function coverageCacheDirectory(): string + { + if (!$this->hasCoverageCacheDirectory()) { + throw new NoCoverageCacheDirectoryException; + } + + return $this->coverageCacheDirectory; + } + + public function source(): Source + { + return $this->source; + } + + public function testResultCacheFile(): string + { + return $this->testResultCacheFile; + } + + public function ignoreDeprecatedCodeUnitsFromCodeCoverage(): bool + { + return $this->ignoreDeprecatedCodeUnitsFromCodeCoverage; + } + + public function disableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore; + } + + public function pathCoverage(): bool + { + return $this->pathCoverage; + } + + public function hasCoverageReport(): bool + { + return $this->hasCoverageClover() || + $this->hasCoverageCobertura() || + $this->hasCoverageCrap4j() || + $this->hasCoverageHtml() || + $this->hasCoverageOpenClover() || + $this->hasCoveragePhp() || + $this->hasCoverageText() || + $this->hasCoverageXml(); + } + + /** + * @phpstan-assert-if-true !null $this->coverageClover + */ + public function hasCoverageClover(): bool + { + return $this->coverageClover !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageClover(): string + { + if (!$this->hasCoverageClover()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageClover; + } + + /** + * @phpstan-assert-if-true !null $this->coverageCobertura + */ + public function hasCoverageCobertura(): bool + { + return $this->coverageCobertura !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageCobertura(): string + { + if (!$this->hasCoverageCobertura()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageCobertura; + } + + /** + * @phpstan-assert-if-true !null $this->coverageCrap4j + */ + public function hasCoverageCrap4j(): bool + { + return $this->coverageCrap4j !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageCrap4j(): string + { + if (!$this->hasCoverageCrap4j()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageCrap4j; + } + + public function coverageCrap4jThreshold(): int + { + return $this->coverageCrap4jThreshold; + } + + /** + * @phpstan-assert-if-true !null $this->coverageHtml + */ + public function hasCoverageHtml(): bool + { + return $this->coverageHtml !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageHtml(): string + { + if (!$this->hasCoverageHtml()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageHtml; + } + + public function coverageHtmlLowUpperBound(): int + { + return $this->coverageHtmlLowUpperBound; + } + + public function coverageHtmlHighLowerBound(): int + { + return $this->coverageHtmlHighLowerBound; + } + + public function coverageHtmlColorSuccessLow(): string + { + return $this->coverageHtmlColorSuccessLow; + } + + public function coverageHtmlColorSuccessMedium(): string + { + return $this->coverageHtmlColorSuccessMedium; + } + + public function coverageHtmlColorSuccessHigh(): string + { + return $this->coverageHtmlColorSuccessHigh; + } + + public function coverageHtmlColorWarning(): string + { + return $this->coverageHtmlColorWarning; + } + + public function coverageHtmlColorDanger(): string + { + return $this->coverageHtmlColorDanger; + } + + /** + * @phpstan-assert-if-true !null $this->coverageHtmlCustomCssFile + */ + public function hasCoverageHtmlCustomCssFile(): bool + { + return $this->coverageHtmlCustomCssFile !== null; + } + + /** + * @throws NoCustomCssFileException + */ + public function coverageHtmlCustomCssFile(): string + { + if (!$this->hasCoverageHtmlCustomCssFile()) { + throw new NoCustomCssFileException; + } + + return $this->coverageHtmlCustomCssFile; + } + + /** + * @phpstan-assert-if-true !null $this->coverageOpenClover + */ + public function hasCoverageOpenClover(): bool + { + return $this->coverageOpenClover !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageOpenClover(): string + { + if (!$this->hasCoverageOpenClover()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageOpenClover; + } + + /** + * @phpstan-assert-if-true !null $this->coveragePhp + */ + public function hasCoveragePhp(): bool + { + return $this->coveragePhp !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coveragePhp(): string + { + if (!$this->hasCoveragePhp()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coveragePhp; + } + + /** + * @phpstan-assert-if-true !null $this->coverageText + */ + public function hasCoverageText(): bool + { + return $this->coverageText !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageText(): string + { + if (!$this->hasCoverageText()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageText; + } + + public function coverageTextShowUncoveredFiles(): bool + { + return $this->coverageTextShowUncoveredFiles; + } + + public function coverageTextShowOnlySummary(): bool + { + return $this->coverageTextShowOnlySummary; + } + + /** + * @phpstan-assert-if-true !null $this->coverageXml + */ + public function hasCoverageXml(): bool + { + return $this->coverageXml !== null; + } + + /** + * @throws CodeCoverageReportNotConfiguredException + */ + public function coverageXml(): string + { + if (!$this->hasCoverageXml()) { + throw new CodeCoverageReportNotConfiguredException; + } + + return $this->coverageXml; + } + + public function coverageXmlIncludeSource(): bool + { + return $this->coverageXmlIncludeSource; + } + + public function failOnAllIssues(): bool + { + return $this->failOnAllIssues; + } + + public function failOnDeprecation(): bool + { + return $this->failOnDeprecation; + } + + public function failOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation; + } + + public function failOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice; + } + + public function failOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning; + } + + public function failOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite; + } + + public function failOnIncomplete(): bool + { + return $this->failOnIncomplete; + } + + public function failOnNotice(): bool + { + return $this->failOnNotice; + } + + public function failOnRisky(): bool + { + return $this->failOnRisky; + } + + public function failOnSkipped(): bool + { + return $this->failOnSkipped; + } + + public function failOnWarning(): bool + { + return $this->failOnWarning; + } + + public function doNotFailOnDeprecation(): bool + { + return $this->doNotFailOnDeprecation; + } + + public function doNotFailOnPhpunitDeprecation(): bool + { + return $this->doNotFailOnPhpunitDeprecation; + } + + public function doNotFailOnPhpunitNotice(): bool + { + return $this->doNotFailOnPhpunitNotice; + } + + public function doNotFailOnPhpunitWarning(): bool + { + return $this->doNotFailOnPhpunitWarning; + } + + public function doNotFailOnEmptyTestSuite(): bool + { + return $this->doNotFailOnEmptyTestSuite; + } + + public function doNotFailOnIncomplete(): bool + { + return $this->doNotFailOnIncomplete; + } + + public function doNotFailOnNotice(): bool + { + return $this->doNotFailOnNotice; + } + + public function doNotFailOnRisky(): bool + { + return $this->doNotFailOnRisky; + } + + public function doNotFailOnSkipped(): bool + { + return $this->doNotFailOnSkipped; + } + + public function doNotFailOnWarning(): bool + { + return $this->doNotFailOnWarning; + } + + public function stopOnDefect(): bool + { + return $this->stopOnDefect; + } + + public function stopOnDeprecation(): bool + { + return $this->stopOnDeprecation; + } + + /** + * @phpstan-assert-if-true !null $this->specificDeprecationToStopOn + */ + public function hasSpecificDeprecationToStopOn(): bool + { + return $this->specificDeprecationToStopOn !== null; + } + + /** + * @throws SpecificDeprecationToStopOnNotConfiguredException + */ + public function specificDeprecationToStopOn(): string + { + if (!$this->hasSpecificDeprecationToStopOn()) { + throw new SpecificDeprecationToStopOnNotConfiguredException; + } + + return $this->specificDeprecationToStopOn; + } + + public function stopOnError(): bool + { + return $this->stopOnError; + } + + public function stopOnFailure(): bool + { + return $this->stopOnFailure; + } + + public function stopOnIncomplete(): bool + { + return $this->stopOnIncomplete; + } + + public function stopOnNotice(): bool + { + return $this->stopOnNotice; + } + + public function stopOnRisky(): bool + { + return $this->stopOnRisky; + } + + public function stopOnSkipped(): bool + { + return $this->stopOnSkipped; + } + + public function stopOnWarning(): bool + { + return $this->stopOnWarning; + } + + public function outputToStandardErrorStream(): bool + { + return $this->outputToStandardErrorStream; + } + + public function columns(): int + { + return $this->columns; + } + + public function noExtensions(): bool + { + return $this->noExtensions; + } + + /** + * @phpstan-assert-if-true !null $this->pharExtensionDirectory + */ + public function hasPharExtensionDirectory(): bool + { + return $this->pharExtensionDirectory !== null; + } + + /** + * @throws NoPharExtensionDirectoryException + * + * @return non-empty-string + */ + public function pharExtensionDirectory(): string + { + if (!$this->hasPharExtensionDirectory()) { + throw new NoPharExtensionDirectoryException; + } + + return $this->pharExtensionDirectory; + } + + /** + * @return list}> + */ + public function extensionBootstrappers(): array + { + return $this->extensionBootstrappers; + } + + public function backupGlobals(): bool + { + return $this->backupGlobals; + } + + public function backupStaticProperties(): bool + { + return $this->backupStaticProperties; + } + + public function beStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState; + } + + public function colors(): bool + { + return $this->colors; + } + + public function processIsolation(): bool + { + return $this->processIsolation; + } + + public function enforceTimeLimit(): bool + { + return $this->enforceTimeLimit; + } + + public function defaultTimeLimit(): int + { + return $this->defaultTimeLimit; + } + + public function timeoutForSmallTests(): int + { + return $this->timeoutForSmallTests; + } + + public function timeoutForMediumTests(): int + { + return $this->timeoutForMediumTests; + } + + public function timeoutForLargeTests(): int + { + return $this->timeoutForLargeTests; + } + + public function reportUselessTests(): bool + { + return $this->reportUselessTests; + } + + public function strictCoverage(): bool + { + return $this->strictCoverage; + } + + public function disallowTestOutput(): bool + { + return $this->disallowTestOutput; + } + + public function displayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues; + } + + public function displayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests; + } + + public function displayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests; + } + + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + + public function displayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations; + } + + public function displayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices; + } + + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors; + } + + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices; + } + + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + + public function reverseDefectList(): bool + { + return $this->reverseDefectList; + } + + public function requireCoverageMetadata(): bool + { + return $this->requireCoverageMetadata; + } + + public function noProgress(): bool + { + return $this->noProgress; + } + + public function noResults(): bool + { + return $this->noResults; + } + + public function noOutput(): bool + { + return $this->noOutput; + } + + public function executionOrder(): int + { + return $this->executionOrder; + } + + public function executionOrderDefects(): int + { + return $this->executionOrderDefects; + } + + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + + /** + * @phpstan-assert-if-true !null $this->logfileTeamcity + */ + public function hasLogfileTeamcity(): bool + { + return $this->logfileTeamcity !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTeamcity(): string + { + if (!$this->hasLogfileTeamcity()) { + throw new LoggingNotConfiguredException; + } + + return $this->logfileTeamcity; + } + + /** + * @phpstan-assert-if-true !null $this->logfileJunit + */ + public function hasLogfileJunit(): bool + { + return $this->logfileJunit !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logfileJunit(): string + { + if (!$this->hasLogfileJunit()) { + throw new LoggingNotConfiguredException; + } + + return $this->logfileJunit; + } + + /** + * @phpstan-assert-if-true !null $this->logfileOtr + */ + public function hasLogfileOtr(): bool + { + return $this->logfileOtr !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logfileOtr(): string + { + if (!$this->hasLogfileOtr()) { + throw new LoggingNotConfiguredException; + } + + return $this->logfileOtr; + } + + public function includeGitInformationInOtrLogfile(): bool + { + return $this->includeGitInformationInOtrLogfile; + } + + /** + * @phpstan-assert-if-true !null $this->logfileTestdoxHtml + */ + public function hasLogfileTestdoxHtml(): bool + { + return $this->logfileTestdoxHtml !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTestdoxHtml(): string + { + if (!$this->hasLogfileTestdoxHtml()) { + throw new LoggingNotConfiguredException; + } + + return $this->logfileTestdoxHtml; + } + + /** + * @phpstan-assert-if-true !null $this->logfileTestdoxText + */ + public function hasLogfileTestdoxText(): bool + { + return $this->logfileTestdoxText !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logfileTestdoxText(): string + { + if (!$this->hasLogfileTestdoxText()) { + throw new LoggingNotConfiguredException; + } + + return $this->logfileTestdoxText; + } + + /** + * @phpstan-assert-if-true !null $this->logEventsText + */ + public function hasLogEventsText(): bool + { + return $this->logEventsText !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logEventsText(): string + { + if (!$this->hasLogEventsText()) { + throw new LoggingNotConfiguredException; + } + + return $this->logEventsText; + } + + /** + * @phpstan-assert-if-true !null $this->logEventsVerboseText + */ + public function hasLogEventsVerboseText(): bool + { + return $this->logEventsVerboseText !== null; + } + + /** + * @throws LoggingNotConfiguredException + */ + public function logEventsVerboseText(): string + { + if (!$this->hasLogEventsVerboseText()) { + throw new LoggingNotConfiguredException; + } + + return $this->logEventsVerboseText; + } + + public function outputIsTeamCity(): bool + { + return $this->teamCityOutput; + } + + public function outputIsTestDox(): bool + { + return $this->testDoxOutput; + } + + public function testDoxOutputWithSummary(): bool + { + return $this->testDoxOutputSummary; + } + + /** + * @phpstan-assert-if-true !empty $this->testsCovering + */ + public function hasTestsCovering(): bool + { + return $this->testsCovering !== null; + } + + /** + * @throws FilterNotConfiguredException + * + * @return list + */ + public function testsCovering(): array + { + if (!$this->hasTestsCovering()) { + throw new FilterNotConfiguredException; + } + + return $this->testsCovering; + } + + /** + * @phpstan-assert-if-true !empty $this->testsUsing + */ + public function hasTestsUsing(): bool + { + return $this->testsUsing !== null; + } + + /** + * @throws FilterNotConfiguredException + * + * @return list + */ + public function testsUsing(): array + { + if (!$this->hasTestsUsing()) { + throw new FilterNotConfiguredException; + } + + return $this->testsUsing; + } + + /** + * @phpstan-assert-if-true !empty $this->testsRequiringPhpExtension + */ + public function hasTestsRequiringPhpExtension(): bool + { + return $this->testsRequiringPhpExtension !== null; + } + + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function testsRequiringPhpExtension(): array + { + if (!$this->hasTestsRequiringPhpExtension()) { + throw new FilterNotConfiguredException; + } + + return $this->testsRequiringPhpExtension; + } + + /** + * @phpstan-assert-if-true !null $this->filter + */ + public function hasFilter(): bool + { + return $this->filter !== null; + } + + /** + * @throws FilterNotConfiguredException + */ + public function filter(): string + { + if (!$this->hasFilter()) { + throw new FilterNotConfiguredException; + } + + return $this->filter; + } + + /** + * @phpstan-assert-if-true !null $this->excludeFilter + */ + public function hasExcludeFilter(): bool + { + return $this->excludeFilter !== null; + } + + /** + * @throws FilterNotConfiguredException + */ + public function excludeFilter(): string + { + if (!$this->hasExcludeFilter()) { + throw new FilterNotConfiguredException; + } + + return $this->excludeFilter; + } + + /** + * @phpstan-assert-if-true !empty $this->groups + */ + public function hasGroups(): bool + { + return $this->groups !== []; + } + + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function groups(): array + { + if (!$this->hasGroups()) { + throw new FilterNotConfiguredException; + } + + return $this->groups; + } + + /** + * @phpstan-assert-if-true !empty $this->excludeGroups + */ + public function hasExcludeGroups(): bool + { + return $this->excludeGroups !== []; + } + + /** + * @throws FilterNotConfiguredException + * + * @return non-empty-list + */ + public function excludeGroups(): array + { + if (!$this->hasExcludeGroups()) { + throw new FilterNotConfiguredException; + } + + return $this->excludeGroups; + } + + public function randomOrderSeed(): int + { + return $this->randomOrderSeed; + } + + public function includeUncoveredFiles(): bool + { + return $this->includeUncoveredFiles; + } + + public function testSuite(): TestSuiteCollection + { + return $this->testSuite; + } + + /** + * @return list + */ + public function includeTestSuites(): array + { + if ($this->includeTestSuite === '') { + return []; + } + + return explode(',', $this->includeTestSuite); + } + + /** + * @return list + */ + public function excludeTestSuites(): array + { + if ($this->excludeTestSuite === '') { + return []; + } + + return explode(',', $this->excludeTestSuite); + } + + /** + * @phpstan-assert-if-true !null $this->defaultTestSuite + */ + public function hasDefaultTestSuite(): bool + { + return $this->defaultTestSuite !== null; + } + + /** + * @throws NoDefaultTestSuiteException + */ + public function defaultTestSuite(): string + { + if (!$this->hasDefaultTestSuite()) { + throw new NoDefaultTestSuiteException; + } + + return $this->defaultTestSuite; + } + + public function ignoreTestSelectionInXmlConfiguration(): bool + { + return $this->ignoreTestSelectionInXmlConfiguration; + } + + /** + * @return non-empty-list + */ + public function testSuffixes(): array + { + return $this->testSuffixes; + } + + public function php(): Php + { + return $this->php; + } + + public function controlGarbageCollector(): bool + { + return $this->controlGarbageCollector; + } + + public function numberOfTestsBeforeGarbageCollection(): int + { + return $this->numberOfTestsBeforeGarbageCollection; + } + + /** + * @phpstan-assert-if-true !null $this->generateBaseline + */ + public function hasGenerateBaseline(): bool + { + return $this->generateBaseline !== null; + } + + /** + * @throws NoBaselineException + * + * @return non-empty-string + */ + public function generateBaseline(): string + { + if (!$this->hasGenerateBaseline()) { + throw new NoBaselineException; + } + + return $this->generateBaseline; + } + + public function debug(): bool + { + return $this->debug; + } + + public function withTelemetry(): bool + { + return $this->withTelemetry; + } + + /** + * @return non-negative-int + */ + public function shortenArraysForExportThreshold(): int + { + return $this->shortenArraysForExportThreshold; + } +} diff --git a/src/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php b/src/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php new file mode 100644 index 00000000000..6146df2b558 --- /dev/null +++ b/src/TextUI/Configuration/Exception/BootstrapScriptDoesNotExistException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapScriptDoesNotExistException extends RuntimeException implements Exception +{ + public function __construct(string $filename) + { + parent::__construct( + sprintf( + 'Cannot open bootstrap script "%s"', + $filename, + ), + ); + } +} diff --git a/src/TextUI/Configuration/Exception/BootstrapScriptException.php b/src/TextUI/Configuration/Exception/BootstrapScriptException.php new file mode 100644 index 00000000000..123b9aeea0c --- /dev/null +++ b/src/TextUI/Configuration/Exception/BootstrapScriptException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class BootstrapScriptException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/CannotFindSchemaException.php b/src/TextUI/Configuration/Exception/CannotFindSchemaException.php new file mode 100644 index 00000000000..6eef052db7a --- /dev/null +++ b/src/TextUI/Configuration/Exception/CannotFindSchemaException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotFindSchemaException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php b/src/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php new file mode 100644 index 00000000000..83faa0a2d67 --- /dev/null +++ b/src/TextUI/Configuration/Exception/CodeCoverageReportNotConfiguredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CodeCoverageReportNotConfiguredException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php b/src/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php new file mode 100644 index 00000000000..e95e09428d0 --- /dev/null +++ b/src/TextUI/Configuration/Exception/ConfigurationCannotBeBuiltException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ConfigurationCannotBeBuiltException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/Exception.php b/src/TextUI/Configuration/Exception/Exception.php new file mode 100644 index 00000000000..dc49125a5f6 --- /dev/null +++ b/src/TextUI/Configuration/Exception/Exception.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends \PHPUnit\TextUI\Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/FilterNotConfiguredException.php b/src/TextUI/Configuration/Exception/FilterNotConfiguredException.php new file mode 100644 index 00000000000..5ae4331f6c5 --- /dev/null +++ b/src/TextUI/Configuration/Exception/FilterNotConfiguredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class FilterNotConfiguredException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/LoggingNotConfiguredException.php b/src/TextUI/Configuration/Exception/LoggingNotConfiguredException.php new file mode 100644 index 00000000000..63cf9b07010 --- /dev/null +++ b/src/TextUI/Configuration/Exception/LoggingNotConfiguredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class LoggingNotConfiguredException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoBaselineException.php b/src/TextUI/Configuration/Exception/NoBaselineException.php new file mode 100644 index 00000000000..7611dceb17d --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoBaselineException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoBaselineException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoBootstrapException.php b/src/TextUI/Configuration/Exception/NoBootstrapException.php new file mode 100644 index 00000000000..ff1bddf0ea2 --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoBootstrapException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoBootstrapException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoCacheDirectoryException.php b/src/TextUI/Configuration/Exception/NoCacheDirectoryException.php new file mode 100644 index 00000000000..215fe21f6f8 --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoCacheDirectoryException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCacheDirectoryException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoConfigurationFileException.php b/src/TextUI/Configuration/Exception/NoConfigurationFileException.php new file mode 100644 index 00000000000..f8ceb80ba2e --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoConfigurationFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoConfigurationFileException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php b/src/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php new file mode 100644 index 00000000000..113950b5d3d --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoCoverageCacheDirectoryException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCoverageCacheDirectoryException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoCustomCssFileException.php b/src/TextUI/Configuration/Exception/NoCustomCssFileException.php new file mode 100644 index 00000000000..e524c8db50a --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoCustomCssFileException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoCustomCssFileException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoDefaultTestSuiteException.php b/src/TextUI/Configuration/Exception/NoDefaultTestSuiteException.php new file mode 100644 index 00000000000..96e7a7ada86 --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoDefaultTestSuiteException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoDefaultTestSuiteException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php b/src/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php new file mode 100644 index 00000000000..ce573ca79ec --- /dev/null +++ b/src/TextUI/Configuration/Exception/NoPharExtensionDirectoryException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class NoPharExtensionDirectoryException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php b/src/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php new file mode 100644 index 00000000000..73074db1306 --- /dev/null +++ b/src/TextUI/Configuration/Exception/SpecificDeprecationToStopOnNotConfiguredException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SpecificDeprecationToStopOnNotConfiguredException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Merger.php b/src/TextUI/Configuration/Merger.php new file mode 100644 index 00000000000..c5fd7ce927e --- /dev/null +++ b/src/TextUI/Configuration/Merger.php @@ -0,0 +1,1079 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const DIRECTORY_SEPARATOR; +use const PATH_SEPARATOR; +use function array_diff; +use function assert; +use function dirname; +use function explode; +use function is_int; +use function realpath; +use function time; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\TextUI\XmlConfiguration\LoadedFromFileConfiguration; +use PHPUnit\TextUI\XmlConfiguration\SchemaDetector; +use PHPUnit\Util\Filesystem; +use SebastianBergmann\CodeCoverage\Report\Html\Colors; +use SebastianBergmann\CodeCoverage\Report\Thresholds; +use SebastianBergmann\Environment\Console; +use SebastianBergmann\Invoker\Invoker; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Merger +{ + /** + * @throws \PHPUnit\TextUI\XmlConfiguration\Exception + * @throws Exception + * @throws NoCustomCssFileException + */ + public function merge(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): Configuration + { + $configurationFile = null; + + if ($xmlConfiguration->wasLoadedFromFile()) { + assert($xmlConfiguration instanceof LoadedFromFileConfiguration); + + $configurationFile = $xmlConfiguration->filename(); + } + + $bootstrap = null; + + if ($cliConfiguration->hasBootstrap()) { + $bootstrap = $cliConfiguration->bootstrap(); + } elseif ($xmlConfiguration->phpunit()->hasBootstrap()) { + $bootstrap = $xmlConfiguration->phpunit()->bootstrap(); + } + + if ($cliConfiguration->hasCacheResult()) { + $cacheResult = $cliConfiguration->cacheResult(); + } else { + $cacheResult = $xmlConfiguration->phpunit()->cacheResult(); + } + + $cacheDirectory = null; + $coverageCacheDirectory = null; + + if ($cliConfiguration->hasCacheDirectory() && Filesystem::createDirectory($cliConfiguration->cacheDirectory())) { + $cacheDirectory = realpath($cliConfiguration->cacheDirectory()); + } elseif ($xmlConfiguration->phpunit()->hasCacheDirectory() && Filesystem::createDirectory($xmlConfiguration->phpunit()->cacheDirectory())) { + $cacheDirectory = realpath($xmlConfiguration->phpunit()->cacheDirectory()); + } + + if ($cacheDirectory !== null) { + $coverageCacheDirectory = $cacheDirectory . DIRECTORY_SEPARATOR . 'code-coverage'; + $testResultCacheFile = $cacheDirectory . DIRECTORY_SEPARATOR . 'test-results'; + } + + if (!isset($testResultCacheFile)) { + if ($xmlConfiguration->wasLoadedFromFile()) { + $testResultCacheFile = dirname(realpath($xmlConfiguration->filename())) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; + } else { + $candidate = realpath($_SERVER['PHP_SELF']); + + if ($candidate) { + $testResultCacheFile = dirname($candidate) . DIRECTORY_SEPARATOR . '.phpunit.result.cache'; + } else { + $testResultCacheFile = '.phpunit.result.cache'; + } + } + } + + if ($cliConfiguration->hasDisableCodeCoverageIgnore()) { + $disableCodeCoverageIgnore = $cliConfiguration->disableCodeCoverageIgnore(); + } else { + $disableCodeCoverageIgnore = $xmlConfiguration->codeCoverage()->disableCodeCoverageIgnore(); + } + + if ($cliConfiguration->hasFailOnAllIssues()) { + $failOnAllIssues = $cliConfiguration->failOnAllIssues(); + } else { + $failOnAllIssues = $xmlConfiguration->phpunit()->failOnAllIssues(); + } + + if ($cliConfiguration->hasFailOnDeprecation()) { + $failOnDeprecation = $cliConfiguration->failOnDeprecation(); + } else { + $failOnDeprecation = $xmlConfiguration->phpunit()->failOnDeprecation(); + } + + if ($cliConfiguration->hasFailOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = $cliConfiguration->failOnPhpunitDeprecation(); + } else { + $failOnPhpunitDeprecation = $xmlConfiguration->phpunit()->failOnPhpunitDeprecation(); + } + + if ($cliConfiguration->hasFailOnPhpunitNotice()) { + $failOnPhpunitNotice = $cliConfiguration->failOnPhpunitNotice(); + } else { + $failOnPhpunitNotice = $xmlConfiguration->phpunit()->failOnPhpunitNotice(); + } + + if ($cliConfiguration->hasFailOnPhpunitWarning()) { + $failOnPhpunitWarning = $cliConfiguration->failOnPhpunitWarning(); + } else { + $failOnPhpunitWarning = $xmlConfiguration->phpunit()->failOnPhpunitWarning(); + } + + if ($cliConfiguration->hasFailOnEmptyTestSuite()) { + $failOnEmptyTestSuite = $cliConfiguration->failOnEmptyTestSuite(); + } else { + $failOnEmptyTestSuite = $xmlConfiguration->phpunit()->failOnEmptyTestSuite(); + } + + if ($cliConfiguration->hasFailOnIncomplete()) { + $failOnIncomplete = $cliConfiguration->failOnIncomplete(); + } else { + $failOnIncomplete = $xmlConfiguration->phpunit()->failOnIncomplete(); + } + + if ($cliConfiguration->hasFailOnNotice()) { + $failOnNotice = $cliConfiguration->failOnNotice(); + } else { + $failOnNotice = $xmlConfiguration->phpunit()->failOnNotice(); + } + + if ($cliConfiguration->hasFailOnRisky()) { + $failOnRisky = $cliConfiguration->failOnRisky(); + } else { + $failOnRisky = $xmlConfiguration->phpunit()->failOnRisky(); + } + + if ($cliConfiguration->hasFailOnSkipped()) { + $failOnSkipped = $cliConfiguration->failOnSkipped(); + } else { + $failOnSkipped = $xmlConfiguration->phpunit()->failOnSkipped(); + } + + if ($cliConfiguration->hasFailOnWarning()) { + $failOnWarning = $cliConfiguration->failOnWarning(); + } else { + $failOnWarning = $xmlConfiguration->phpunit()->failOnWarning(); + } + + $doNotFailOnDeprecation = false; + + if ($cliConfiguration->hasDoNotFailOnDeprecation()) { + $doNotFailOnDeprecation = $cliConfiguration->doNotFailOnDeprecation(); + } + + $doNotFailOnPhpunitDeprecation = false; + + if ($cliConfiguration->hasDoNotFailOnPhpunitDeprecation()) { + $doNotFailOnPhpunitDeprecation = $cliConfiguration->doNotFailOnPhpunitDeprecation(); + } + + $doNotFailOnPhpunitNotice = false; + + if ($cliConfiguration->hasDoNotFailOnPhpunitNotice()) { + $doNotFailOnPhpunitNotice = $cliConfiguration->doNotFailOnPhpunitNotice(); + } + + $doNotFailOnPhpunitWarning = false; + + if ($cliConfiguration->hasDoNotFailOnPhpunitWarning()) { + $doNotFailOnPhpunitWarning = $cliConfiguration->doNotFailOnPhpunitWarning(); + } + + $doNotFailOnEmptyTestSuite = false; + + if ($cliConfiguration->hasDoNotFailOnEmptyTestSuite()) { + $doNotFailOnEmptyTestSuite = $cliConfiguration->doNotFailOnEmptyTestSuite(); + } + + $doNotFailOnIncomplete = false; + + if ($cliConfiguration->hasDoNotFailOnIncomplete()) { + $doNotFailOnIncomplete = $cliConfiguration->doNotFailOnIncomplete(); + } + + $doNotFailOnNotice = false; + + if ($cliConfiguration->hasDoNotFailOnNotice()) { + $doNotFailOnNotice = $cliConfiguration->doNotFailOnNotice(); + } + + $doNotFailOnRisky = false; + + if ($cliConfiguration->hasDoNotFailOnRisky()) { + $doNotFailOnRisky = $cliConfiguration->doNotFailOnRisky(); + } + + $doNotFailOnSkipped = false; + + if ($cliConfiguration->hasDoNotFailOnSkipped()) { + $doNotFailOnSkipped = $cliConfiguration->doNotFailOnSkipped(); + } + + $doNotFailOnWarning = false; + + if ($cliConfiguration->hasDoNotFailOnWarning()) { + $doNotFailOnWarning = $cliConfiguration->doNotFailOnWarning(); + } + + if ($cliConfiguration->hasStopOnDefect()) { + $stopOnDefect = $cliConfiguration->stopOnDefect(); + } else { + $stopOnDefect = $xmlConfiguration->phpunit()->stopOnDefect(); + } + + if ($cliConfiguration->hasStopOnDeprecation()) { + $stopOnDeprecation = $cliConfiguration->stopOnDeprecation(); + } else { + $stopOnDeprecation = $xmlConfiguration->phpunit()->stopOnDeprecation(); + } + + $specificDeprecationToStopOn = null; + + if ($cliConfiguration->hasSpecificDeprecationToStopOn()) { + $specificDeprecationToStopOn = $cliConfiguration->specificDeprecationToStopOn(); + } + + if ($cliConfiguration->hasStopOnError()) { + $stopOnError = $cliConfiguration->stopOnError(); + } else { + $stopOnError = $xmlConfiguration->phpunit()->stopOnError(); + } + + if ($cliConfiguration->hasStopOnFailure()) { + $stopOnFailure = $cliConfiguration->stopOnFailure(); + } else { + $stopOnFailure = $xmlConfiguration->phpunit()->stopOnFailure(); + } + + if ($cliConfiguration->hasStopOnIncomplete()) { + $stopOnIncomplete = $cliConfiguration->stopOnIncomplete(); + } else { + $stopOnIncomplete = $xmlConfiguration->phpunit()->stopOnIncomplete(); + } + + if ($cliConfiguration->hasStopOnNotice()) { + $stopOnNotice = $cliConfiguration->stopOnNotice(); + } else { + $stopOnNotice = $xmlConfiguration->phpunit()->stopOnNotice(); + } + + if ($cliConfiguration->hasStopOnRisky()) { + $stopOnRisky = $cliConfiguration->stopOnRisky(); + } else { + $stopOnRisky = $xmlConfiguration->phpunit()->stopOnRisky(); + } + + if ($cliConfiguration->hasStopOnSkipped()) { + $stopOnSkipped = $cliConfiguration->stopOnSkipped(); + } else { + $stopOnSkipped = $xmlConfiguration->phpunit()->stopOnSkipped(); + } + + if ($cliConfiguration->hasStopOnWarning()) { + $stopOnWarning = $cliConfiguration->stopOnWarning(); + } else { + $stopOnWarning = $xmlConfiguration->phpunit()->stopOnWarning(); + } + + if ($cliConfiguration->hasStderr() && $cliConfiguration->stderr()) { + $outputToStandardErrorStream = true; + } else { + $outputToStandardErrorStream = $xmlConfiguration->phpunit()->stderr(); + } + + if ($cliConfiguration->hasColumns()) { + $columns = $cliConfiguration->columns(); + } else { + $columns = $xmlConfiguration->phpunit()->columns(); + } + + if ($columns === 'max') { + $columns = (new Console)->getNumberOfColumns(); + } + + if ($columns < 16) { + $columns = 16; + + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + 'Less than 16 columns requested, number of columns set to 16', + ); + } + + assert(is_int($columns)); + + $noExtensions = false; + + if ($cliConfiguration->hasNoExtensions() && $cliConfiguration->noExtensions()) { + $noExtensions = true; + } + + $pharExtensionDirectory = null; + + if ($xmlConfiguration->phpunit()->hasExtensionsDirectory()) { + $pharExtensionDirectory = $xmlConfiguration->phpunit()->extensionsDirectory(); + } + + $extensionBootstrappers = []; + + if ($cliConfiguration->hasExtensions()) { + foreach ($cliConfiguration->extensions() as $extension) { + $extensionBootstrappers[] = [ + 'className' => $extension, + 'parameters' => [], + ]; + } + } + + foreach ($xmlConfiguration->extensions() as $extension) { + $extensionBootstrappers[] = [ + 'className' => $extension->className(), + 'parameters' => $extension->parameters(), + ]; + } + + if ($cliConfiguration->hasPathCoverage() && $cliConfiguration->pathCoverage()) { + $pathCoverage = $cliConfiguration->pathCoverage(); + } else { + $pathCoverage = $xmlConfiguration->codeCoverage()->pathCoverage(); + } + + $defaultColors = Colors::default(); + $defaultThresholds = Thresholds::default(); + + $coverageClover = null; + $coverageCobertura = null; + $coverageCrap4j = null; + $coverageCrap4jThreshold = 30; + $coverageHtml = null; + $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); + $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); + $coverageHtmlColorSuccessLow = $defaultColors->successLow(); + $coverageHtmlColorSuccessMedium = $defaultColors->successMedium(); + $coverageHtmlColorSuccessHigh = $defaultColors->successHigh(); + $coverageHtmlColorWarning = $defaultColors->warning(); + $coverageHtmlColorDanger = $defaultColors->danger(); + $coverageHtmlCustomCssFile = null; + $coverageOpenClover = null; + $coveragePhp = null; + $coverageText = null; + $coverageTextShowUncoveredFiles = false; + $coverageTextShowOnlySummary = false; + $coverageXml = null; + $coverageXmlIncludeSource = true; + $coverageFromXmlConfiguration = true; + + if ($cliConfiguration->hasNoCoverage() && $cliConfiguration->noCoverage()) { + $coverageFromXmlConfiguration = false; + } + + if ($cliConfiguration->hasCoverageClover()) { + $coverageClover = $cliConfiguration->coverageClover(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasClover()) { + $coverageClover = $xmlConfiguration->codeCoverage()->clover()->target()->path(); + } + + if ($cliConfiguration->hasCoverageCobertura()) { + $coverageCobertura = $cliConfiguration->coverageCobertura(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCobertura()) { + $coverageCobertura = $xmlConfiguration->codeCoverage()->cobertura()->target()->path(); + } + + if ($xmlConfiguration->codeCoverage()->hasCrap4j()) { + $coverageCrap4jThreshold = $xmlConfiguration->codeCoverage()->crap4j()->threshold(); + } + + if ($cliConfiguration->hasCoverageCrap4J()) { + $coverageCrap4j = $cliConfiguration->coverageCrap4J(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasCrap4j()) { + $coverageCrap4j = $xmlConfiguration->codeCoverage()->crap4j()->target()->path(); + } + + if ($xmlConfiguration->codeCoverage()->hasHtml()) { + $coverageHtmlHighLowerBound = $xmlConfiguration->codeCoverage()->html()->highLowerBound(); + $coverageHtmlLowUpperBound = $xmlConfiguration->codeCoverage()->html()->lowUpperBound(); + + if ($coverageHtmlLowUpperBound > $coverageHtmlHighLowerBound) { + $coverageHtmlLowUpperBound = $defaultThresholds->lowUpperBound(); + $coverageHtmlHighLowerBound = $defaultThresholds->highLowerBound(); + } + + $coverageHtmlColorSuccessLow = $xmlConfiguration->codeCoverage()->html()->colorSuccessLow(); + $coverageHtmlColorSuccessMedium = $xmlConfiguration->codeCoverage()->html()->colorSuccessMedium(); + $coverageHtmlColorSuccessHigh = $xmlConfiguration->codeCoverage()->html()->colorSuccessHigh(); + $coverageHtmlColorWarning = $xmlConfiguration->codeCoverage()->html()->colorWarning(); + $coverageHtmlColorDanger = $xmlConfiguration->codeCoverage()->html()->colorDanger(); + + if ($xmlConfiguration->codeCoverage()->html()->hasCustomCssFile()) { + $coverageHtmlCustomCssFile = $xmlConfiguration->codeCoverage()->html()->customCssFile(); + } + } + + if ($cliConfiguration->hasCoverageHtml()) { + $coverageHtml = $cliConfiguration->coverageHtml(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasHtml()) { + $coverageHtml = $xmlConfiguration->codeCoverage()->html()->target()->path(); + } + + if ($cliConfiguration->hasCoverageOpenClover()) { + $coverageOpenClover = $cliConfiguration->coverageOpenClover(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasOpenClover()) { + $coverageOpenClover = $xmlConfiguration->codeCoverage()->openClover()->target()->path(); + } + + if ($cliConfiguration->hasCoveragePhp()) { + $coveragePhp = $cliConfiguration->coveragePhp(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasPhp()) { + $coveragePhp = $xmlConfiguration->codeCoverage()->php()->target()->path(); + } + + if ($xmlConfiguration->codeCoverage()->hasText()) { + $coverageTextShowUncoveredFiles = $xmlConfiguration->codeCoverage()->text()->showUncoveredFiles(); + $coverageTextShowOnlySummary = $xmlConfiguration->codeCoverage()->text()->showOnlySummary(); + } + + if ($cliConfiguration->hasCoverageTextShowUncoveredFiles()) { + $coverageTextShowUncoveredFiles = $cliConfiguration->coverageTextShowUncoveredFiles(); + } + + if ($cliConfiguration->hasCoverageTextShowOnlySummary()) { + $coverageTextShowOnlySummary = $cliConfiguration->coverageTextShowOnlySummary(); + } + + if ($cliConfiguration->hasCoverageText()) { + $coverageText = $cliConfiguration->coverageText(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasText()) { + $coverageText = $xmlConfiguration->codeCoverage()->text()->target()->path(); + } + + if ($cliConfiguration->hasCoverageXml()) { + $coverageXml = $cliConfiguration->coverageXml(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { + $coverageXml = $xmlConfiguration->codeCoverage()->xml()->target()->path(); + } + + if ($cliConfiguration->hasExcludeSourceFromXmlCoverage()) { + $coverageXmlIncludeSource = !$cliConfiguration->excludeSourceFromXmlCoverage(); + } elseif ($coverageFromXmlConfiguration && $xmlConfiguration->codeCoverage()->hasXml()) { + $coverageXmlIncludeSource = $xmlConfiguration->codeCoverage()->xml()->includeSource(); + } + + if ($cliConfiguration->hasBackupGlobals()) { + $backupGlobals = $cliConfiguration->backupGlobals(); + } else { + $backupGlobals = $xmlConfiguration->phpunit()->backupGlobals(); + } + + if ($cliConfiguration->hasBackupStaticProperties()) { + $backupStaticProperties = $cliConfiguration->backupStaticProperties(); + } else { + $backupStaticProperties = $xmlConfiguration->phpunit()->backupStaticProperties(); + } + + if ($cliConfiguration->hasBeStrictAboutChangesToGlobalState()) { + $beStrictAboutChangesToGlobalState = $cliConfiguration->beStrictAboutChangesToGlobalState(); + } else { + $beStrictAboutChangesToGlobalState = $xmlConfiguration->phpunit()->beStrictAboutChangesToGlobalState(); + } + + if ($cliConfiguration->hasProcessIsolation()) { + $processIsolation = $cliConfiguration->processIsolation(); + } else { + $processIsolation = $xmlConfiguration->phpunit()->processIsolation(); + } + + if ($cliConfiguration->hasEnforceTimeLimit()) { + $enforceTimeLimit = $cliConfiguration->enforceTimeLimit(); + } else { + $enforceTimeLimit = $xmlConfiguration->phpunit()->enforceTimeLimit(); + } + + if ($enforceTimeLimit && !(new Invoker)->canInvokeWithTimeout()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + 'The pcntl extension is required for enforcing time limits', + ); + } + + if ($cliConfiguration->hasDefaultTimeLimit()) { + $defaultTimeLimit = $cliConfiguration->defaultTimeLimit(); + } else { + $defaultTimeLimit = $xmlConfiguration->phpunit()->defaultTimeLimit(); + } + + $timeoutForSmallTests = $xmlConfiguration->phpunit()->timeoutForSmallTests(); + $timeoutForMediumTests = $xmlConfiguration->phpunit()->timeoutForMediumTests(); + $timeoutForLargeTests = $xmlConfiguration->phpunit()->timeoutForLargeTests(); + + if ($cliConfiguration->hasReportUselessTests()) { + $reportUselessTests = $cliConfiguration->reportUselessTests(); + } else { + $reportUselessTests = $xmlConfiguration->phpunit()->beStrictAboutTestsThatDoNotTestAnything(); + } + + if ($cliConfiguration->hasStrictCoverage()) { + $strictCoverage = $cliConfiguration->strictCoverage(); + } else { + $strictCoverage = $xmlConfiguration->phpunit()->beStrictAboutCoverageMetadata(); + } + + if ($cliConfiguration->hasDisallowTestOutput()) { + $disallowTestOutput = $cliConfiguration->disallowTestOutput(); + } else { + $disallowTestOutput = $xmlConfiguration->phpunit()->beStrictAboutOutputDuringTests(); + } + + if ($cliConfiguration->hasDisplayDetailsOnAllIssues()) { + $displayDetailsOnAllIssues = $cliConfiguration->displayDetailsOnAllIssues(); + } else { + $displayDetailsOnAllIssues = $xmlConfiguration->phpunit()->displayDetailsOnAllIssues(); + } + + if ($cliConfiguration->hasDisplayDetailsOnIncompleteTests()) { + $displayDetailsOnIncompleteTests = $cliConfiguration->displayDetailsOnIncompleteTests(); + } else { + $displayDetailsOnIncompleteTests = $xmlConfiguration->phpunit()->displayDetailsOnIncompleteTests(); + } + + if ($cliConfiguration->hasDisplayDetailsOnSkippedTests()) { + $displayDetailsOnSkippedTests = $cliConfiguration->displayDetailsOnSkippedTests(); + } else { + $displayDetailsOnSkippedTests = $xmlConfiguration->phpunit()->displayDetailsOnSkippedTests(); + } + + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerDeprecations()) { + $displayDetailsOnTestsThatTriggerDeprecations = $cliConfiguration->displayDetailsOnTestsThatTriggerDeprecations(); + } else { + $displayDetailsOnTestsThatTriggerDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerDeprecations(); + } + + if ($cliConfiguration->hasDisplayDetailsOnPhpunitDeprecations()) { + $displayDetailsOnPhpunitDeprecations = $cliConfiguration->displayDetailsOnPhpunitDeprecations(); + } else { + $displayDetailsOnPhpunitDeprecations = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitDeprecations(); + } + + if ($cliConfiguration->hasDisplayDetailsOnPhpunitNotices()) { + $displayDetailsOnPhpunitNotices = $cliConfiguration->displayDetailsOnPhpunitNotices(); + } else { + $displayDetailsOnPhpunitNotices = $xmlConfiguration->phpunit()->displayDetailsOnPhpunitNotices(); + } + + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerErrors()) { + $displayDetailsOnTestsThatTriggerErrors = $cliConfiguration->displayDetailsOnTestsThatTriggerErrors(); + } else { + $displayDetailsOnTestsThatTriggerErrors = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerErrors(); + } + + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerNotices()) { + $displayDetailsOnTestsThatTriggerNotices = $cliConfiguration->displayDetailsOnTestsThatTriggerNotices(); + } else { + $displayDetailsOnTestsThatTriggerNotices = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerNotices(); + } + + if ($cliConfiguration->hasDisplayDetailsOnTestsThatTriggerWarnings()) { + $displayDetailsOnTestsThatTriggerWarnings = $cliConfiguration->displayDetailsOnTestsThatTriggerWarnings(); + } else { + $displayDetailsOnTestsThatTriggerWarnings = $xmlConfiguration->phpunit()->displayDetailsOnTestsThatTriggerWarnings(); + } + + if ($cliConfiguration->hasReverseList()) { + $reverseDefectList = $cliConfiguration->reverseList(); + } else { + $reverseDefectList = $xmlConfiguration->phpunit()->reverseDefectList(); + } + + $requireCoverageMetadata = $xmlConfiguration->phpunit()->requireCoverageMetadata(); + + if ($cliConfiguration->hasExecutionOrder()) { + $executionOrder = $cliConfiguration->executionOrder(); + } else { + $executionOrder = $xmlConfiguration->phpunit()->executionOrder(); + } + + $executionOrderDefects = TestSuiteSorter::ORDER_DEFAULT; + + if ($cliConfiguration->hasExecutionOrderDefects()) { + $executionOrderDefects = $cliConfiguration->executionOrderDefects(); + } elseif ($xmlConfiguration->phpunit()->defectsFirst()) { + $executionOrderDefects = TestSuiteSorter::ORDER_DEFECTS_FIRST; + } + + if ($cliConfiguration->hasResolveDependencies()) { + $resolveDependencies = $cliConfiguration->resolveDependencies(); + } else { + $resolveDependencies = $xmlConfiguration->phpunit()->resolveDependencies(); + } + + $colors = false; + $colorsSupported = (new Console)->hasColorSupport(); + + if ($cliConfiguration->hasColors()) { + if ($cliConfiguration->colors() === Configuration::COLOR_ALWAYS) { + $colors = true; + } elseif ($colorsSupported && $cliConfiguration->colors() === Configuration::COLOR_AUTO) { + $colors = true; + } + } elseif ($xmlConfiguration->phpunit()->colors() === Configuration::COLOR_ALWAYS) { + $colors = true; + } elseif ($colorsSupported && $xmlConfiguration->phpunit()->colors() === Configuration::COLOR_AUTO) { + $colors = true; + } + + $logfileTeamcity = null; + $logfileJunit = null; + $logfileOtr = null; + $logfileTestdoxHtml = null; + $logfileTestdoxText = null; + $loggingFromXmlConfiguration = true; + + if ($cliConfiguration->hasNoLogging() && $cliConfiguration->noLogging()) { + $loggingFromXmlConfiguration = false; + } + + if ($cliConfiguration->hasTeamcityLogfile()) { + $logfileTeamcity = $cliConfiguration->teamcityLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTeamCity()) { + $logfileTeamcity = $xmlConfiguration->logging()->teamCity()->target()->path(); + } + + if ($cliConfiguration->hasJunitLogfile()) { + $logfileJunit = $cliConfiguration->junitLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasJunit()) { + $logfileJunit = $xmlConfiguration->logging()->junit()->target()->path(); + } + + if ($cliConfiguration->hasOtrLogfile()) { + $logfileOtr = $cliConfiguration->otrLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasOtr()) { + $logfileOtr = $xmlConfiguration->logging()->otr()->target()->path(); + } + + $includeGitInformationInOtrLogfile = false; + + if ($cliConfiguration->hasIncludeGitInformationInOtrLogfile()) { + $includeGitInformationInOtrLogfile = $cliConfiguration->includeGitInformationInOtrLogfile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasOtr()) { + $includeGitInformationInOtrLogfile = $xmlConfiguration->logging()->otr()->includeGitInformation(); + } + + if ($cliConfiguration->hasTestdoxHtmlFile()) { + $logfileTestdoxHtml = $cliConfiguration->testdoxHtmlFile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxHtml()) { + $logfileTestdoxHtml = $xmlConfiguration->logging()->testDoxHtml()->target()->path(); + } + + if ($cliConfiguration->hasTestdoxTextFile()) { + $logfileTestdoxText = $cliConfiguration->testdoxTextFile(); + } elseif ($loggingFromXmlConfiguration && $xmlConfiguration->logging()->hasTestDoxText()) { + $logfileTestdoxText = $xmlConfiguration->logging()->testDoxText()->target()->path(); + } + + $logEventsText = null; + + if ($cliConfiguration->hasLogEventsText()) { + $logEventsText = $cliConfiguration->logEventsText(); + } + + $logEventsVerboseText = null; + + if ($cliConfiguration->hasLogEventsVerboseText()) { + $logEventsVerboseText = $cliConfiguration->logEventsVerboseText(); + } + + $teamCityOutput = false; + + if ($cliConfiguration->hasTeamCityPrinter() && $cliConfiguration->teamCityPrinter()) { + $teamCityOutput = true; + } + + if ($cliConfiguration->hasTestDoxPrinter() && $cliConfiguration->testdoxPrinter()) { + $testDoxOutput = true; + } else { + $testDoxOutput = $xmlConfiguration->phpunit()->testdoxPrinter(); + } + + if ($cliConfiguration->hasTestDoxPrinterSummary() && $cliConfiguration->testdoxPrinterSummary()) { + $testDoxOutputSummary = true; + } else { + $testDoxOutputSummary = $xmlConfiguration->phpunit()->testdoxPrinterSummary(); + } + + $noProgress = false; + + if ($cliConfiguration->hasNoProgress() && $cliConfiguration->noProgress()) { + $noProgress = true; + } + + $noResults = false; + + if ($cliConfiguration->hasNoResults() && $cliConfiguration->noResults()) { + $noResults = true; + } + + $noOutput = false; + + if ($cliConfiguration->hasNoOutput() && $cliConfiguration->noOutput()) { + $noOutput = true; + } + + $testsCovering = null; + + if ($cliConfiguration->hasTestsCovering()) { + $testsCovering = $cliConfiguration->testsCovering(); + } + + $testsUsing = null; + + if ($cliConfiguration->hasTestsUsing()) { + $testsUsing = $cliConfiguration->testsUsing(); + } + + $testsRequiringPhpExtension = null; + + if ($cliConfiguration->hasTestsRequiringPhpExtension()) { + $testsRequiringPhpExtension = $cliConfiguration->testsRequiringPhpExtension(); + } + + $filter = null; + + if ($cliConfiguration->hasFilter()) { + $filter = $cliConfiguration->filter(); + } + + $excludeFilter = null; + + if ($cliConfiguration->hasExcludeFilter()) { + $excludeFilter = $cliConfiguration->excludeFilter(); + } + + $ignoreTestSelectionInXmlConfiguration = false; + + if ($cliConfiguration->hasAll()) { + $ignoreTestSelectionInXmlConfiguration = true; + } + + $groups = []; + + if ($cliConfiguration->hasGroups()) { + $groups = $cliConfiguration->groups(); + } elseif (!$ignoreTestSelectionInXmlConfiguration) { + $groups = $xmlConfiguration->groups()->include()->asArrayOfStrings(); + } + + $excludeGroups = []; + + if ($cliConfiguration->hasExcludeGroups()) { + $excludeGroups = $cliConfiguration->excludeGroups(); + } elseif (!$ignoreTestSelectionInXmlConfiguration) { + $excludeGroups = $xmlConfiguration->groups()->exclude()->asArrayOfStrings(); + } + + $excludeGroups = array_diff($excludeGroups, $groups); + + if ($cliConfiguration->hasRandomOrderSeed()) { + $randomOrderSeed = $cliConfiguration->randomOrderSeed(); + } else { + $randomOrderSeed = time(); + } + + if ($xmlConfiguration->wasLoadedFromFile() && $xmlConfiguration->hasValidationErrors()) { + if ((new SchemaDetector)->detect($xmlConfiguration->filename())->detected()) { + EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation( + 'Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"!', + ); + } else { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + "Test results may not be as expected because the XML configuration file did not pass validation:\n" . + $xmlConfiguration->validationErrors(), + ); + } + } + + $includeUncoveredFiles = $xmlConfiguration->codeCoverage()->includeUncoveredFiles(); + + $includePaths = []; + + if ($cliConfiguration->hasIncludePath()) { + foreach (explode(PATH_SEPARATOR, $cliConfiguration->includePath()) as $includePath) { + $includePaths[] = new Directory($includePath); + } + } + + foreach ($xmlConfiguration->php()->includePaths() as $includePath) { + $includePaths[] = $includePath; + } + + $iniSettings = []; + + if ($cliConfiguration->hasIniSettings()) { + foreach ($cliConfiguration->iniSettings() as $name => $value) { + $iniSettings[] = new IniSetting($name, $value); + } + } + + foreach ($xmlConfiguration->php()->iniSettings() as $iniSetting) { + $iniSettings[] = $iniSetting; + } + + $includeTestSuite = ''; + + if ($cliConfiguration->hasTestSuite()) { + $includeTestSuite = $cliConfiguration->testSuite(); + } elseif ($xmlConfiguration->phpunit()->hasDefaultTestSuite()) { + $includeTestSuite = $xmlConfiguration->phpunit()->defaultTestSuite(); + } + + $excludeTestSuite = ''; + + if ($cliConfiguration->hasExcludedTestSuite()) { + $excludeTestSuite = $cliConfiguration->excludedTestSuite(); + } + + $testSuffixes = ['Test.php', '.phpt']; + + if ($cliConfiguration->hasTestSuffixes()) { + $testSuffixes = $cliConfiguration->testSuffixes(); + } + + $sourceIncludeDirectories = []; + + if ($cliConfiguration->hasCoverageFilter()) { + foreach ($cliConfiguration->coverageFilter() as $directory) { + $sourceIncludeDirectories[] = new FilterDirectory($directory, '', '.php'); + } + } + + foreach ($xmlConfiguration->source()->includeDirectories() as $directory) { + $sourceIncludeDirectories[] = $directory; + } + + $sourceIncludeFiles = $xmlConfiguration->source()->includeFiles(); + $sourceExcludeDirectories = $xmlConfiguration->source()->excludeDirectories(); + $sourceExcludeFiles = $xmlConfiguration->source()->excludeFiles(); + + $useBaseline = null; + $generateBaseline = null; + + if (!$cliConfiguration->hasGenerateBaseline()) { + if ($cliConfiguration->hasUseBaseline()) { + $useBaseline = $cliConfiguration->useBaseline(); + } elseif ($xmlConfiguration->source()->hasBaseline()) { + $useBaseline = $xmlConfiguration->source()->baseline(); + } + } else { + $generateBaseline = $cliConfiguration->generateBaseline(); + } + + assert($useBaseline !== ''); + assert($generateBaseline !== ''); + + if ($failOnAllIssues) { + $displayDetailsOnAllIssues = true; + } + + if ($failOnDeprecation && !$doNotFailOnDeprecation) { + $displayDetailsOnTestsThatTriggerDeprecations = true; + } + + if ($failOnPhpunitDeprecation && !$doNotFailOnPhpunitDeprecation) { + $displayDetailsOnPhpunitDeprecations = true; + } + + if ($failOnPhpunitNotice && !$doNotFailOnPhpunitNotice) { + $displayDetailsOnPhpunitNotices = true; + } + + if ($failOnNotice && !$doNotFailOnNotice) { + $displayDetailsOnTestsThatTriggerNotices = true; + } + + if ($failOnWarning && !$doNotFailOnWarning) { + $displayDetailsOnTestsThatTriggerWarnings = true; + } + + if ($failOnIncomplete && !$doNotFailOnIncomplete) { + $displayDetailsOnIncompleteTests = true; + } + + if ($failOnSkipped && !$doNotFailOnSkipped) { + $displayDetailsOnSkippedTests = true; + } + + return new Configuration( + $cliConfiguration->arguments(), + $configurationFile, + $bootstrap, + $xmlConfiguration->phpunit()->bootstrapForTestSuite(), + $cacheResult, + $cacheDirectory, + $coverageCacheDirectory, + new Source( + $useBaseline, + $cliConfiguration->ignoreBaseline(), + FilterDirectoryCollection::fromArray($sourceIncludeDirectories), + $sourceIncludeFiles, + $sourceExcludeDirectories, + $sourceExcludeFiles, + $xmlConfiguration->source()->restrictNotices(), + $xmlConfiguration->source()->restrictWarnings(), + $xmlConfiguration->source()->ignoreSuppressionOfDeprecations(), + $xmlConfiguration->source()->ignoreSuppressionOfPhpDeprecations(), + $xmlConfiguration->source()->ignoreSuppressionOfErrors(), + $xmlConfiguration->source()->ignoreSuppressionOfNotices(), + $xmlConfiguration->source()->ignoreSuppressionOfPhpNotices(), + $xmlConfiguration->source()->ignoreSuppressionOfWarnings(), + $xmlConfiguration->source()->ignoreSuppressionOfPhpWarnings(), + $xmlConfiguration->source()->deprecationTriggers(), + $xmlConfiguration->source()->ignoreSelfDeprecations(), + $xmlConfiguration->source()->ignoreDirectDeprecations(), + $xmlConfiguration->source()->ignoreIndirectDeprecations(), + ), + $testResultCacheFile, + $coverageClover, + $coverageCobertura, + $coverageCrap4j, + $coverageCrap4jThreshold, + $coverageHtml, + $coverageHtmlLowUpperBound, + $coverageHtmlHighLowerBound, + $coverageHtmlColorSuccessLow, + $coverageHtmlColorSuccessMedium, + $coverageHtmlColorSuccessHigh, + $coverageHtmlColorWarning, + $coverageHtmlColorDanger, + $coverageHtmlCustomCssFile, + $coverageOpenClover, + $coveragePhp, + $coverageText, + $coverageTextShowUncoveredFiles, + $coverageTextShowOnlySummary, + $coverageXml, + $coverageXmlIncludeSource, + $pathCoverage, + $xmlConfiguration->codeCoverage()->ignoreDeprecatedCodeUnits(), + $disableCodeCoverageIgnore, + $failOnAllIssues, + $failOnDeprecation, + $failOnPhpunitDeprecation, + $failOnPhpunitNotice, + $failOnPhpunitWarning, + $failOnEmptyTestSuite, + $failOnIncomplete, + $failOnNotice, + $failOnRisky, + $failOnSkipped, + $failOnWarning, + $doNotFailOnDeprecation, + $doNotFailOnPhpunitDeprecation, + $doNotFailOnPhpunitNotice, + $doNotFailOnPhpunitWarning, + $doNotFailOnEmptyTestSuite, + $doNotFailOnIncomplete, + $doNotFailOnNotice, + $doNotFailOnRisky, + $doNotFailOnSkipped, + $doNotFailOnWarning, + $stopOnDefect, + $stopOnDeprecation, + $specificDeprecationToStopOn, + $stopOnError, + $stopOnFailure, + $stopOnIncomplete, + $stopOnNotice, + $stopOnRisky, + $stopOnSkipped, + $stopOnWarning, + $outputToStandardErrorStream, + $columns, + $noExtensions, + $pharExtensionDirectory, + $extensionBootstrappers, + $backupGlobals, + $backupStaticProperties, + $beStrictAboutChangesToGlobalState, + $colors, + $processIsolation, + $enforceTimeLimit, + $defaultTimeLimit, + $timeoutForSmallTests, + $timeoutForMediumTests, + $timeoutForLargeTests, + $reportUselessTests, + $strictCoverage, + $disallowTestOutput, + $displayDetailsOnAllIssues, + $displayDetailsOnIncompleteTests, + $displayDetailsOnSkippedTests, + $displayDetailsOnTestsThatTriggerDeprecations, + $displayDetailsOnPhpunitDeprecations, + $displayDetailsOnPhpunitNotices, + $displayDetailsOnTestsThatTriggerErrors, + $displayDetailsOnTestsThatTriggerNotices, + $displayDetailsOnTestsThatTriggerWarnings, + $reverseDefectList, + $requireCoverageMetadata, + $noProgress, + $noResults, + $noOutput, + $executionOrder, + $executionOrderDefects, + $resolveDependencies, + $logfileTeamcity, + $logfileJunit, + $logfileOtr, + $includeGitInformationInOtrLogfile, + $logfileTestdoxHtml, + $logfileTestdoxText, + $logEventsText, + $logEventsVerboseText, + $teamCityOutput, + $testDoxOutput, + $testDoxOutputSummary, + $testsCovering, + $testsUsing, + $testsRequiringPhpExtension, + $filter, + $excludeFilter, + $groups, + $excludeGroups, + $randomOrderSeed, + $includeUncoveredFiles, + $xmlConfiguration->testSuite(), + $includeTestSuite, + $excludeTestSuite, + $xmlConfiguration->phpunit()->hasDefaultTestSuite() ? $xmlConfiguration->phpunit()->defaultTestSuite() : null, + $ignoreTestSelectionInXmlConfiguration, + $testSuffixes, + new Php( + DirectoryCollection::fromArray($includePaths), + IniSettingCollection::fromArray($iniSettings), + $xmlConfiguration->php()->constants(), + $xmlConfiguration->php()->globalVariables(), + $xmlConfiguration->php()->envVariables(), + $xmlConfiguration->php()->postVariables(), + $xmlConfiguration->php()->getVariables(), + $xmlConfiguration->php()->cookieVariables(), + $xmlConfiguration->php()->serverVariables(), + $xmlConfiguration->php()->filesVariables(), + $xmlConfiguration->php()->requestVariables(), + ), + $xmlConfiguration->phpunit()->controlGarbageCollector(), + $xmlConfiguration->phpunit()->numberOfTestsBeforeGarbageCollection(), + $generateBaseline, + $cliConfiguration->debug(), + $cliConfiguration->withTelemetry(), + $xmlConfiguration->phpunit()->shortenArraysForExportThreshold(), + ); + } +} diff --git a/src/TextUI/Configuration/PhpHandler.php b/src/TextUI/Configuration/PhpHandler.php new file mode 100644 index 00000000000..3aa13160e16 --- /dev/null +++ b/src/TextUI/Configuration/PhpHandler.php @@ -0,0 +1,123 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PATH_SEPARATOR; +use function constant; +use function define; +use function defined; +use function getenv; +use function implode; +use function ini_get; +use function ini_set; +use function putenv; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class PhpHandler +{ + public function handle(Php $configuration): void + { + $this->handleIncludePaths($configuration->includePaths()); + $this->handleIniSettings($configuration->iniSettings()); + $this->handleConstants($configuration->constants()); + $this->handleGlobalVariables($configuration->globalVariables()); + $this->handleServerVariables($configuration->serverVariables()); + $this->handleEnvVariables($configuration->envVariables()); + $this->handleVariables('_POST', $configuration->postVariables()); + $this->handleVariables('_GET', $configuration->getVariables()); + $this->handleVariables('_COOKIE', $configuration->cookieVariables()); + $this->handleVariables('_FILES', $configuration->filesVariables()); + $this->handleVariables('_REQUEST', $configuration->requestVariables()); + } + + private function handleIncludePaths(DirectoryCollection $includePaths): void + { + if (!$includePaths->isEmpty()) { + $includePathsAsStrings = []; + + foreach ($includePaths as $includePath) { + $includePathsAsStrings[] = $includePath->path(); + } + + ini_set( + 'include_path', + implode(PATH_SEPARATOR, $includePathsAsStrings) . + PATH_SEPARATOR . + ini_get('include_path'), + ); + } + } + + private function handleIniSettings(IniSettingCollection $iniSettings): void + { + foreach ($iniSettings as $iniSetting) { + $value = $iniSetting->value(); + + if (defined($value)) { + $value = (string) constant($value); + } + + ini_set($iniSetting->name(), $value); + } + } + + private function handleConstants(ConstantCollection $constants): void + { + foreach ($constants as $constant) { + if (!defined($constant->name())) { + define($constant->name(), $constant->value()); + } + } + } + + private function handleGlobalVariables(VariableCollection $variables): void + { + foreach ($variables as $variable) { + $GLOBALS[$variable->name()] = $variable->value(); + } + } + + private function handleServerVariables(VariableCollection $variables): void + { + foreach ($variables as $variable) { + $_SERVER[$variable->name()] = $variable->value(); + } + } + + private function handleVariables(string $target, VariableCollection $variables): void + { + foreach ($variables as $variable) { + $GLOBALS[$target][$variable->name()] = $variable->value(); + } + } + + private function handleEnvVariables(VariableCollection $variables): void + { + foreach ($variables as $variable) { + $name = $variable->name(); + $value = $variable->value(); + $force = $variable->force(); + + if ($force || getenv($name) === false) { + putenv("{$name}={$value}"); + } + + $value = getenv($name); + + if ($force || !isset($_ENV[$name])) { + $_ENV[$name] = $value; + } + } + } +} diff --git a/src/TextUI/Configuration/Registry.php b/src/TextUI/Configuration/Registry.php new file mode 100644 index 00000000000..ad8075235d2 --- /dev/null +++ b/src/TextUI/Configuration/Registry.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function assert; +use function file_get_contents; +use function file_put_contents; +use function serialize; +use function unserialize; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\TextUI\CliArguments\Configuration as CliConfiguration; +use PHPUnit\TextUI\CliArguments\Exception; +use PHPUnit\TextUI\XmlConfiguration\Configuration as XmlConfiguration; +use PHPUnit\Util\VersionComparisonOperator; + +/** + * CLI options and XML configuration are static within a single PHPUnit process. + * It is therefore okay to use a Singleton registry here. + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Registry +{ + private static ?Configuration $instance = null; + + public static function saveTo(string $path): bool + { + $result = file_put_contents( + $path, + serialize(self::get()), + ); + + if ($result) { + return true; + } + + // @codeCoverageIgnoreStart + return false; + // @codeCoverageIgnoreEnd + } + + /** + * This method is used by the "run test(s) in separate process" templates. + * + * @noinspection PhpUnused + * + * @codeCoverageIgnore + */ + public static function loadFrom(string $path): void + { + $buffer = file_get_contents($path); + + assert($buffer !== false); + + self::$instance = unserialize( + $buffer, + [ + 'allowed_classes' => [ + Configuration::class, + Php::class, + ConstantCollection::class, + Constant::class, + IniSettingCollection::class, + IniSetting::class, + VariableCollection::class, + Variable::class, + DirectoryCollection::class, + Directory::class, + FileCollection::class, + File::class, + FilterDirectoryCollection::class, + FilterDirectory::class, + TestDirectoryCollection::class, + TestDirectory::class, + TestFileCollection::class, + TestFile::class, + TestSuiteCollection::class, + TestSuite::class, + VersionComparisonOperator::class, + Source::class, + ], + ], + ); + } + + public static function get(): Configuration + { + assert(self::$instance instanceof Configuration); + + return self::$instance; + } + + /** + * @throws \PHPUnit\TextUI\XmlConfiguration\Exception + * @throws Exception + * @throws NoCustomCssFileException + */ + public static function init(CliConfiguration $cliConfiguration, XmlConfiguration $xmlConfiguration): Configuration + { + self::$instance = (new Merger)->merge($cliConfiguration, $xmlConfiguration); + + EventFacade::emitter()->testRunnerConfigured(self::$instance); + + return self::$instance; + } +} diff --git a/src/TextUI/Configuration/SourceFilter.php b/src/TextUI/Configuration/SourceFilter.php new file mode 100644 index 00000000000..845a9b3763f --- /dev/null +++ b/src/TextUI/Configuration/SourceFilter.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SourceFilter +{ + private static ?self $instance = null; + + /** + * @var array + */ + private readonly array $map; + + public static function instance(): self + { + if (self::$instance === null) { + self::$instance = new self( + (new SourceMapper)->map( + Registry::get()->source(), + ), + ); + } + + return self::$instance; + } + + /** + * @param array $map + */ + public function __construct(array $map) + { + $this->map = $map; + } + + public function includes(string $path): bool + { + return isset($this->map[$path]); + } +} diff --git a/src/TextUI/Configuration/SourceMapper.php b/src/TextUI/Configuration/SourceMapper.php new file mode 100644 index 00000000000..c2c5483822f --- /dev/null +++ b/src/TextUI/Configuration/SourceMapper.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function realpath; +use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use SplObjectStorage; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SourceMapper +{ + /** + * @var ?SplObjectStorage> + */ + private static ?SplObjectStorage $files = null; + + /** + * @return array + */ + public function map(Source $source): array + { + if (self::$files === null) { + self::$files = new SplObjectStorage; + } + + if (isset(self::$files[$source])) { + return self::$files[$source]; + } + + $files = []; + + $directories = $this->aggregateDirectories($source->includeDirectories()); + + foreach ($directories as $path => [$prefixes, $suffixes]) { + foreach ((new FileIteratorFacade)->getFilesAsArray($path, $suffixes, $prefixes) as $file) { + $file = realpath($file); + + if (!$file) { + continue; + } + + $files[$file] = true; + } + } + + foreach ($source->includeFiles() as $file) { + $file = realpath($file->path()); + + if (!$file) { + continue; + } + + $files[$file] = true; + } + + $directories = $this->aggregateDirectories($source->excludeDirectories()); + + foreach ($directories as $path => [$prefixes, $suffixes]) { + foreach ((new FileIteratorFacade)->getFilesAsArray($path, $suffixes, $prefixes) as $file) { + $file = realpath($file); + + if (!$file) { + continue; + } + + if (!isset($files[$file])) { + continue; + } + + unset($files[$file]); + } + } + + foreach ($source->excludeFiles() as $file) { + $file = realpath($file->path()); + + if (!$file) { + continue; + } + + if (!isset($files[$file])) { + continue; + } + + unset($files[$file]); + } + + self::$files[$source] = $files; + + return $files; + } + + /** + * @return array,list}> + */ + private function aggregateDirectories(FilterDirectoryCollection $directories): array + { + $aggregated = []; + + foreach ($directories as $directory) { + if (!isset($aggregated[$directory->path()])) { + $aggregated[$directory->path()] = [ + 0 => [], + 1 => [], + ]; + } + + $prefix = $directory->prefix(); + + if ($prefix !== '') { + $aggregated[$directory->path()][0][] = $prefix; + } + + $suffix = $directory->suffix(); + + if ($suffix !== '') { + $aggregated[$directory->path()][1][] = $suffix; + } + } + + return $aggregated; + } +} diff --git a/src/TextUI/Configuration/TestSuiteBuilder.php b/src/TextUI/Configuration/TestSuiteBuilder.php new file mode 100644 index 00000000000..a474b02f548 --- /dev/null +++ b/src/TextUI/Configuration/TestSuiteBuilder.php @@ -0,0 +1,151 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PHP_EOL; +use function assert; +use function count; +use function is_dir; +use function is_file; +use function realpath; +use function str_ends_with; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Exception; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\TestSuiteLoader; +use PHPUnit\TextUI\RuntimeException; +use PHPUnit\TextUI\TestDirectoryNotFoundException; +use PHPUnit\TextUI\TestFileNotFoundException; +use PHPUnit\TextUI\XmlConfiguration\TestSuiteMapper; +use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteBuilder +{ + /** + * @throws \PHPUnit\Framework\Exception + * @throws RuntimeException + * @throws TestDirectoryNotFoundException + * @throws TestFileNotFoundException + */ + public function build(Configuration $configuration): TestSuite + { + if ($configuration->hasCliArguments()) { + $arguments = []; + + foreach ($configuration->cliArguments() as $cliArgument) { + $argument = realpath($cliArgument); + + if (!$argument) { + throw new TestFileNotFoundException($cliArgument); + } + + $arguments[] = $argument; + } + + if (count($arguments) === 1) { + $testSuite = $this->testSuiteFromPath( + $arguments[0], + $configuration->testSuffixes(), + ); + } else { + $testSuite = $this->testSuiteFromPathList( + $arguments, + $configuration->testSuffixes(), + ); + } + } + + if (!isset($testSuite)) { + $xmlConfigurationFile = $configuration->hasConfigurationFile() ? $configuration->configurationFile() : 'Root Test Suite'; + + assert($xmlConfigurationFile !== ''); + + $testSuite = (new TestSuiteMapper)->map( + $xmlConfigurationFile, + $configuration->testSuite(), + $configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->includeTestSuites(), + $configuration->ignoreTestSelectionInXmlConfiguration() ? [] : $configuration->excludeTestSuites(), + ); + } + + EventFacade::emitter()->testSuiteLoaded(\PHPUnit\Event\TestSuite\TestSuiteBuilder::from($testSuite)); + + return $testSuite; + } + + /** + * @param non-empty-string $path + * @param list $suffixes + * + * @throws \PHPUnit\Framework\Exception + */ + private function testSuiteFromPath(string $path, array $suffixes, ?TestSuite $suite = null): TestSuite + { + if (str_ends_with($path, '.phpt') && is_file($path)) { + if ($suite === null) { + $suite = TestSuite::empty($path); + } + + $suite->addTestFile($path); + + return $suite; + } + + if (is_dir($path)) { + $files = (new FileIteratorFacade)->getFilesAsArray($path, $suffixes); + + if ($suite === null) { + $suite = TestSuite::empty('CLI Arguments'); + } + + $suite->addTestFiles($files); + + return $suite; + } + + try { + $testClass = (new TestSuiteLoader)->load($path); + } catch (Exception $e) { + print $e->getMessage() . PHP_EOL; + + exit(1); + } + + if ($suite === null) { + return TestSuite::fromClassReflector($testClass); + } + + $suite->addTestSuite($testClass); + + return $suite; + } + + /** + * @param list $paths + * @param list $suffixes + * + * @throws \PHPUnit\Framework\Exception + */ + private function testSuiteFromPathList(array $paths, array $suffixes): TestSuite + { + $suite = TestSuite::empty('CLI Arguments'); + + foreach ($paths as $path) { + $this->testSuiteFromPath($path, $suffixes, $suite); + } + + return $suite; + } +} diff --git a/src/TextUI/Configuration/Value/Constant.php b/src/TextUI/Configuration/Value/Constant.php new file mode 100644 index 00000000000..0ff240dd03e --- /dev/null +++ b/src/TextUI/Configuration/Value/Constant.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Constant +{ + private string $name; + private bool|string $value; + + public function __construct(string $name, bool|string $value) + { + $this->name = $name; + $this->value = $value; + } + + public function name(): string + { + return $this->name; + } + + public function value(): bool|string + { + return $this->value; + } +} diff --git a/src/TextUI/Configuration/Value/ConstantCollection.php b/src/TextUI/Configuration/Value/ConstantCollection.php new file mode 100644 index 00000000000..3e34d7434ec --- /dev/null +++ b/src/TextUI/Configuration/Value/ConstantCollection.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class ConstantCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $constants; + + /** + * @param list $constants + */ + public static function fromArray(array $constants): self + { + return new self(...$constants); + } + + private function __construct(Constant ...$constants) + { + $this->constants = $constants; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->constants; + } + + public function count(): int + { + return count($this->constants); + } + + public function getIterator(): ConstantCollectionIterator + { + return new ConstantCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/ConstantCollectionIterator.php b/src/TextUI/Configuration/Value/ConstantCollectionIterator.php new file mode 100644 index 00000000000..f385b7faf4f --- /dev/null +++ b/src/TextUI/Configuration/Value/ConstantCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class ConstantCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $constants; + private int $position = 0; + + public function __construct(ConstantCollection $constants) + { + $this->constants = $constants->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->constants); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Constant + { + return $this->constants[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/Directory.php b/src/TextUI/Configuration/Value/Directory.php new file mode 100644 index 00000000000..f44e28b1559 --- /dev/null +++ b/src/TextUI/Configuration/Value/Directory.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Directory +{ + private string $path; + + public function __construct(string $path) + { + $this->path = $path; + } + + public function path(): string + { + return $this->path; + } +} diff --git a/src/TextUI/Configuration/Value/DirectoryCollection.php b/src/TextUI/Configuration/Value/DirectoryCollection.php new file mode 100644 index 00000000000..dc1e840c94c --- /dev/null +++ b/src/TextUI/Configuration/Value/DirectoryCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class DirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + + private function __construct(Directory ...$directories) + { + $this->directories = $directories; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + + public function count(): int + { + return count($this->directories); + } + + public function getIterator(): DirectoryCollectionIterator + { + return new DirectoryCollectionIterator($this); + } + + public function isEmpty(): bool + { + return $this->count() === 0; + } +} diff --git a/src/TextUI/Configuration/Value/DirectoryCollectionIterator.php b/src/TextUI/Configuration/Value/DirectoryCollectionIterator.php new file mode 100644 index 00000000000..73d2cff6344 --- /dev/null +++ b/src/TextUI/Configuration/Value/DirectoryCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class DirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + private int $position = 0; + + public function __construct(DirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->directories); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Directory + { + return $this->directories[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/ExtensionBootstrap.php b/src/TextUI/Configuration/Value/ExtensionBootstrap.php new file mode 100644 index 00000000000..09430c7f3f7 --- /dev/null +++ b/src/TextUI/Configuration/Value/ExtensionBootstrap.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ExtensionBootstrap +{ + /** + * @var non-empty-string + */ + private string $className; + + /** + * @var array + */ + private array $parameters; + + /** + * @param non-empty-string $className + * @param array $parameters + */ + public function __construct(string $className, array $parameters) + { + $this->className = $className; + $this->parameters = $parameters; + } + + /** + * @return non-empty-string + */ + public function className(): string + { + return $this->className; + } + + /** + * @return array + */ + public function parameters(): array + { + return $this->parameters; + } +} diff --git a/src/TextUI/Configuration/Value/ExtensionBootstrapCollection.php b/src/TextUI/Configuration/Value/ExtensionBootstrapCollection.php new file mode 100644 index 00000000000..16ca1e07049 --- /dev/null +++ b/src/TextUI/Configuration/Value/ExtensionBootstrapCollection.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use IteratorAggregate; + +/** + * @template-implements IteratorAggregate + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ExtensionBootstrapCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $extensionBootstraps; + + /** + * @param list $extensionBootstraps + */ + public static function fromArray(array $extensionBootstraps): self + { + return new self(...$extensionBootstraps); + } + + private function __construct(ExtensionBootstrap ...$extensionBootstraps) + { + $this->extensionBootstraps = $extensionBootstraps; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->extensionBootstraps; + } + + public function getIterator(): ExtensionBootstrapCollectionIterator + { + return new ExtensionBootstrapCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.php b/src/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.php new file mode 100644 index 00000000000..0b5c20ba15c --- /dev/null +++ b/src/TextUI/Configuration/Value/ExtensionBootstrapCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class ExtensionBootstrapCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $extensionBootstraps; + private int $position = 0; + + public function __construct(ExtensionBootstrapCollection $extensionBootstraps) + { + $this->extensionBootstraps = $extensionBootstraps->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->extensionBootstraps); + } + + public function key(): int + { + return $this->position; + } + + public function current(): ExtensionBootstrap + { + return $this->extensionBootstraps[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/File.php b/src/TextUI/Configuration/Value/File.php new file mode 100644 index 00000000000..85900f47f6c --- /dev/null +++ b/src/TextUI/Configuration/Value/File.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class File +{ + /** + * @var non-empty-string + */ + private string $path; + + /** + * @param non-empty-string $path + */ + public function __construct(string $path) + { + $this->path = $path; + } + + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } +} diff --git a/src/TextUI/Configuration/Value/FileCollection.php b/src/TextUI/Configuration/Value/FileCollection.php new file mode 100644 index 00000000000..61522a5eb6d --- /dev/null +++ b/src/TextUI/Configuration/Value/FileCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class FileCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $files; + + /** + * @param list $files + */ + public static function fromArray(array $files): self + { + return new self(...$files); + } + + private function __construct(File ...$files) + { + $this->files = $files; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->files; + } + + public function count(): int + { + return count($this->files); + } + + public function notEmpty(): bool + { + return $this->files !== []; + } + + public function getIterator(): FileCollectionIterator + { + return new FileCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/FileCollectionIterator.php b/src/TextUI/Configuration/Value/FileCollectionIterator.php new file mode 100644 index 00000000000..91ec8e27638 --- /dev/null +++ b/src/TextUI/Configuration/Value/FileCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class FileCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $files; + private int $position = 0; + + public function __construct(FileCollection $files) + { + $this->files = $files->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->files); + } + + public function key(): int + { + return $this->position; + } + + public function current(): File + { + return $this->files[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/FilterDirectory.php b/src/TextUI/Configuration/Value/FilterDirectory.php new file mode 100644 index 00000000000..52dcd1b1323 --- /dev/null +++ b/src/TextUI/Configuration/Value/FilterDirectory.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class FilterDirectory +{ + /** + * @var non-empty-string + */ + private string $path; + private string $prefix; + private string $suffix; + + /** + * @param non-empty-string $path + */ + public function __construct(string $path, string $prefix, string $suffix) + { + $this->path = $path; + $this->prefix = $prefix; + $this->suffix = $suffix; + } + + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + + public function prefix(): string + { + return $this->prefix; + } + + public function suffix(): string + { + return $this->suffix; + } +} diff --git a/src/TextUI/Configuration/Value/FilterDirectoryCollection.php b/src/TextUI/Configuration/Value/FilterDirectoryCollection.php new file mode 100644 index 00000000000..147f0618f0d --- /dev/null +++ b/src/TextUI/Configuration/Value/FilterDirectoryCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class FilterDirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + + private function __construct(FilterDirectory ...$directories) + { + $this->directories = $directories; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + + public function count(): int + { + return count($this->directories); + } + + public function notEmpty(): bool + { + return $this->directories !== []; + } + + public function getIterator(): FilterDirectoryCollectionIterator + { + return new FilterDirectoryCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.php b/src/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.php new file mode 100644 index 00000000000..737c752f465 --- /dev/null +++ b/src/TextUI/Configuration/Value/FilterDirectoryCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class FilterDirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + private int $position = 0; + + public function __construct(FilterDirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->directories); + } + + public function key(): int + { + return $this->position; + } + + public function current(): FilterDirectory + { + return $this->directories[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/Group.php b/src/TextUI/Configuration/Value/Group.php new file mode 100644 index 00000000000..cb0bdc8aa3e --- /dev/null +++ b/src/TextUI/Configuration/Value/Group.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Group +{ + private string $name; + + public function __construct(string $name) + { + $this->name = $name; + } + + public function name(): string + { + return $this->name; + } +} diff --git a/src/TextUI/Configuration/Value/GroupCollection.php b/src/TextUI/Configuration/Value/GroupCollection.php new file mode 100644 index 00000000000..8232e1f34fc --- /dev/null +++ b/src/TextUI/Configuration/Value/GroupCollection.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class GroupCollection implements IteratorAggregate +{ + /** + * @var list + */ + private array $groups; + + /** + * @param list $groups + */ + public static function fromArray(array $groups): self + { + return new self(...$groups); + } + + private function __construct(Group ...$groups) + { + $this->groups = $groups; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->groups; + } + + /** + * @return list + */ + public function asArrayOfStrings(): array + { + $result = []; + + foreach ($this->groups as $group) { + $result[] = $group->name(); + } + + return $result; + } + + public function isEmpty(): bool + { + return $this->groups === []; + } + + public function getIterator(): GroupCollectionIterator + { + return new GroupCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/GroupCollectionIterator.php b/src/TextUI/Configuration/Value/GroupCollectionIterator.php new file mode 100644 index 00000000000..774808757cb --- /dev/null +++ b/src/TextUI/Configuration/Value/GroupCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class GroupCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $groups; + private int $position = 0; + + public function __construct(GroupCollection $groups) + { + $this->groups = $groups->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->groups); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Group + { + return $this->groups[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/IniSetting.php b/src/TextUI/Configuration/Value/IniSetting.php new file mode 100644 index 00000000000..b4d11665551 --- /dev/null +++ b/src/TextUI/Configuration/Value/IniSetting.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class IniSetting +{ + private string $name; + private string $value; + + public function __construct(string $name, string $value) + { + $this->name = $name; + $this->value = $value; + } + + public function name(): string + { + return $this->name; + } + + public function value(): string + { + return $this->value; + } +} diff --git a/src/TextUI/Configuration/Value/IniSettingCollection.php b/src/TextUI/Configuration/Value/IniSettingCollection.php new file mode 100644 index 00000000000..abfd8fd241b --- /dev/null +++ b/src/TextUI/Configuration/Value/IniSettingCollection.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class IniSettingCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $iniSettings; + + /** + * @param list $iniSettings + */ + public static function fromArray(array $iniSettings): self + { + return new self(...$iniSettings); + } + + private function __construct(IniSetting ...$iniSettings) + { + $this->iniSettings = $iniSettings; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->iniSettings; + } + + public function count(): int + { + return count($this->iniSettings); + } + + public function getIterator(): IniSettingCollectionIterator + { + return new IniSettingCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/IniSettingCollectionIterator.php b/src/TextUI/Configuration/Value/IniSettingCollectionIterator.php new file mode 100644 index 00000000000..cb68c3dd1a4 --- /dev/null +++ b/src/TextUI/Configuration/Value/IniSettingCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class IniSettingCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $iniSettings; + private int $position = 0; + + public function __construct(IniSettingCollection $iniSettings) + { + $this->iniSettings = $iniSettings->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->iniSettings); + } + + public function key(): int + { + return $this->position; + } + + public function current(): IniSetting + { + return $this->iniSettings[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/Php.php b/src/TextUI/Configuration/Value/Php.php new file mode 100644 index 00000000000..0dc4735dca7 --- /dev/null +++ b/src/TextUI/Configuration/Value/Php.php @@ -0,0 +1,100 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Php +{ + private DirectoryCollection $includePaths; + private IniSettingCollection $iniSettings; + private ConstantCollection $constants; + private VariableCollection $globalVariables; + private VariableCollection $envVariables; + private VariableCollection $postVariables; + private VariableCollection $getVariables; + private VariableCollection $cookieVariables; + private VariableCollection $serverVariables; + private VariableCollection $filesVariables; + private VariableCollection $requestVariables; + + public function __construct(DirectoryCollection $includePaths, IniSettingCollection $iniSettings, ConstantCollection $constants, VariableCollection $globalVariables, VariableCollection $envVariables, VariableCollection $postVariables, VariableCollection $getVariables, VariableCollection $cookieVariables, VariableCollection $serverVariables, VariableCollection $filesVariables, VariableCollection $requestVariables) + { + $this->includePaths = $includePaths; + $this->iniSettings = $iniSettings; + $this->constants = $constants; + $this->globalVariables = $globalVariables; + $this->envVariables = $envVariables; + $this->postVariables = $postVariables; + $this->getVariables = $getVariables; + $this->cookieVariables = $cookieVariables; + $this->serverVariables = $serverVariables; + $this->filesVariables = $filesVariables; + $this->requestVariables = $requestVariables; + } + + public function includePaths(): DirectoryCollection + { + return $this->includePaths; + } + + public function iniSettings(): IniSettingCollection + { + return $this->iniSettings; + } + + public function constants(): ConstantCollection + { + return $this->constants; + } + + public function globalVariables(): VariableCollection + { + return $this->globalVariables; + } + + public function envVariables(): VariableCollection + { + return $this->envVariables; + } + + public function postVariables(): VariableCollection + { + return $this->postVariables; + } + + public function getVariables(): VariableCollection + { + return $this->getVariables; + } + + public function cookieVariables(): VariableCollection + { + return $this->cookieVariables; + } + + public function serverVariables(): VariableCollection + { + return $this->serverVariables; + } + + public function filesVariables(): VariableCollection + { + return $this->filesVariables; + } + + public function requestVariables(): VariableCollection + { + return $this->requestVariables; + } +} diff --git a/src/TextUI/Configuration/Value/Source.php b/src/TextUI/Configuration/Value/Source.php new file mode 100644 index 00000000000..b6f61eb07d9 --- /dev/null +++ b/src/TextUI/Configuration/Value/Source.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Source +{ + /** + * @var non-empty-string + */ + private ?string $baseline; + private bool $ignoreBaseline; + private FilterDirectoryCollection $includeDirectories; + private FileCollection $includeFiles; + private FilterDirectoryCollection $excludeDirectories; + private FileCollection $excludeFiles; + private bool $restrictNotices; + private bool $restrictWarnings; + private bool $ignoreSuppressionOfDeprecations; + private bool $ignoreSuppressionOfPhpDeprecations; + private bool $ignoreSuppressionOfErrors; + private bool $ignoreSuppressionOfNotices; + private bool $ignoreSuppressionOfPhpNotices; + private bool $ignoreSuppressionOfWarnings; + private bool $ignoreSuppressionOfPhpWarnings; + private bool $ignoreSelfDeprecations; + private bool $ignoreDirectDeprecations; + private bool $ignoreIndirectDeprecations; + + /** + * @var array{functions: list, methods: list} + */ + private array $deprecationTriggers; + + /** + * @param non-empty-string $baseline + * @param array{functions: list, methods: list} $deprecationTriggers + */ + public function __construct(?string $baseline, bool $ignoreBaseline, FilterDirectoryCollection $includeDirectories, FileCollection $includeFiles, FilterDirectoryCollection $excludeDirectories, FileCollection $excludeFiles, bool $restrictNotices, bool $restrictWarnings, bool $ignoreSuppressionOfDeprecations, bool $ignoreSuppressionOfPhpDeprecations, bool $ignoreSuppressionOfErrors, bool $ignoreSuppressionOfNotices, bool $ignoreSuppressionOfPhpNotices, bool $ignoreSuppressionOfWarnings, bool $ignoreSuppressionOfPhpWarnings, array $deprecationTriggers, bool $ignoreSelfDeprecations, bool $ignoreDirectDeprecations, bool $ignoreIndirectDeprecations) + { + $this->baseline = $baseline; + $this->ignoreBaseline = $ignoreBaseline; + $this->includeDirectories = $includeDirectories; + $this->includeFiles = $includeFiles; + $this->excludeDirectories = $excludeDirectories; + $this->excludeFiles = $excludeFiles; + $this->restrictNotices = $restrictNotices; + $this->restrictWarnings = $restrictWarnings; + $this->ignoreSuppressionOfDeprecations = $ignoreSuppressionOfDeprecations; + $this->ignoreSuppressionOfPhpDeprecations = $ignoreSuppressionOfPhpDeprecations; + $this->ignoreSuppressionOfErrors = $ignoreSuppressionOfErrors; + $this->ignoreSuppressionOfNotices = $ignoreSuppressionOfNotices; + $this->ignoreSuppressionOfPhpNotices = $ignoreSuppressionOfPhpNotices; + $this->ignoreSuppressionOfWarnings = $ignoreSuppressionOfWarnings; + $this->ignoreSuppressionOfPhpWarnings = $ignoreSuppressionOfPhpWarnings; + $this->deprecationTriggers = $deprecationTriggers; + $this->ignoreSelfDeprecations = $ignoreSelfDeprecations; + $this->ignoreDirectDeprecations = $ignoreDirectDeprecations; + $this->ignoreIndirectDeprecations = $ignoreIndirectDeprecations; + } + + /** + * @phpstan-assert-if-true !null $this->baseline + */ + public function useBaseline(): bool + { + return $this->hasBaseline() && !$this->ignoreBaseline; + } + + /** + * @phpstan-assert-if-true !null $this->baseline + */ + public function hasBaseline(): bool + { + return $this->baseline !== null; + } + + /** + * @throws NoBaselineException + * + * @return non-empty-string + */ + public function baseline(): string + { + if (!$this->hasBaseline()) { + throw new NoBaselineException; + } + + return $this->baseline; + } + + public function includeDirectories(): FilterDirectoryCollection + { + return $this->includeDirectories; + } + + public function includeFiles(): FileCollection + { + return $this->includeFiles; + } + + public function excludeDirectories(): FilterDirectoryCollection + { + return $this->excludeDirectories; + } + + public function excludeFiles(): FileCollection + { + return $this->excludeFiles; + } + + public function notEmpty(): bool + { + return $this->includeDirectories->notEmpty() || $this->includeFiles->notEmpty(); + } + + public function restrictNotices(): bool + { + return $this->restrictNotices; + } + + public function restrictWarnings(): bool + { + return $this->restrictWarnings; + } + + public function ignoreSuppressionOfDeprecations(): bool + { + return $this->ignoreSuppressionOfDeprecations; + } + + public function ignoreSuppressionOfPhpDeprecations(): bool + { + return $this->ignoreSuppressionOfPhpDeprecations; + } + + public function ignoreSuppressionOfErrors(): bool + { + return $this->ignoreSuppressionOfErrors; + } + + public function ignoreSuppressionOfNotices(): bool + { + return $this->ignoreSuppressionOfNotices; + } + + public function ignoreSuppressionOfPhpNotices(): bool + { + return $this->ignoreSuppressionOfPhpNotices; + } + + public function ignoreSuppressionOfWarnings(): bool + { + return $this->ignoreSuppressionOfWarnings; + } + + public function ignoreSuppressionOfPhpWarnings(): bool + { + return $this->ignoreSuppressionOfPhpWarnings; + } + + /** + * @return array{functions: list, methods: list} + */ + public function deprecationTriggers(): array + { + return $this->deprecationTriggers; + } + + public function ignoreSelfDeprecations(): bool + { + return $this->ignoreSelfDeprecations; + } + + public function ignoreDirectDeprecations(): bool + { + return $this->ignoreDirectDeprecations; + } + + public function ignoreIndirectDeprecations(): bool + { + return $this->ignoreIndirectDeprecations; + } +} diff --git a/src/TextUI/Configuration/Value/TestDirectory.php b/src/TextUI/Configuration/Value/TestDirectory.php new file mode 100644 index 00000000000..dfe301a941e --- /dev/null +++ b/src/TextUI/Configuration/Value/TestDirectory.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Util\VersionComparisonOperator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestDirectory +{ + /** + * @var non-empty-string + */ + private string $path; + private string $prefix; + private string $suffix; + private string $phpVersion; + private VersionComparisonOperator $phpVersionOperator; + + /** + * @var list + */ + private array $groups; + + /** + * @param non-empty-string $path + * @param list $groups + */ + public function __construct(string $path, string $prefix, string $suffix, string $phpVersion, VersionComparisonOperator $phpVersionOperator, array $groups) + { + $this->path = $path; + $this->prefix = $prefix; + $this->suffix = $suffix; + $this->phpVersion = $phpVersion; + $this->phpVersionOperator = $phpVersionOperator; + $this->groups = $groups; + } + + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + + public function prefix(): string + { + return $this->prefix; + } + + public function suffix(): string + { + return $this->suffix; + } + + public function phpVersion(): string + { + return $this->phpVersion; + } + + public function phpVersionOperator(): VersionComparisonOperator + { + return $this->phpVersionOperator; + } + + /** + * @return list + */ + public function groups(): array + { + return $this->groups; + } +} diff --git a/src/TextUI/Configuration/Value/TestDirectoryCollection.php b/src/TextUI/Configuration/Value/TestDirectoryCollection.php new file mode 100644 index 00000000000..ba867273ce2 --- /dev/null +++ b/src/TextUI/Configuration/Value/TestDirectoryCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestDirectoryCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $directories; + + /** + * @param list $directories + */ + public static function fromArray(array $directories): self + { + return new self(...$directories); + } + + private function __construct(TestDirectory ...$directories) + { + $this->directories = $directories; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->directories; + } + + public function count(): int + { + return count($this->directories); + } + + public function getIterator(): TestDirectoryCollectionIterator + { + return new TestDirectoryCollectionIterator($this); + } + + public function isEmpty(): bool + { + return $this->count() === 0; + } +} diff --git a/src/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php b/src/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php new file mode 100644 index 00000000000..fa57410a633 --- /dev/null +++ b/src/TextUI/Configuration/Value/TestDirectoryCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestDirectoryCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $directories; + private int $position = 0; + + public function __construct(TestDirectoryCollection $directories) + { + $this->directories = $directories->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->directories); + } + + public function key(): int + { + return $this->position; + } + + public function current(): TestDirectory + { + return $this->directories[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/TestFile.php b/src/TextUI/Configuration/Value/TestFile.php new file mode 100644 index 00000000000..e658ff88437 --- /dev/null +++ b/src/TextUI/Configuration/Value/TestFile.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Util\VersionComparisonOperator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestFile +{ + /** + * @var non-empty-string + */ + private string $path; + private string $phpVersion; + private VersionComparisonOperator $phpVersionOperator; + + /** + * @var list + */ + private array $groups; + + /** + * @param non-empty-string $path + * @param list $groups + */ + public function __construct(string $path, string $phpVersion, VersionComparisonOperator $phpVersionOperator, array $groups) + { + $this->path = $path; + $this->phpVersion = $phpVersion; + $this->phpVersionOperator = $phpVersionOperator; + $this->groups = $groups; + } + + /** + * @return non-empty-string + */ + public function path(): string + { + return $this->path; + } + + public function phpVersion(): string + { + return $this->phpVersion; + } + + public function phpVersionOperator(): VersionComparisonOperator + { + return $this->phpVersionOperator; + } + + /** + * @return list + */ + public function groups(): array + { + return $this->groups; + } +} diff --git a/src/TextUI/Configuration/Value/TestFileCollection.php b/src/TextUI/Configuration/Value/TestFileCollection.php new file mode 100644 index 00000000000..6d1ae27993c --- /dev/null +++ b/src/TextUI/Configuration/Value/TestFileCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestFileCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $files; + + /** + * @param list $files + */ + public static function fromArray(array $files): self + { + return new self(...$files); + } + + private function __construct(TestFile ...$files) + { + $this->files = $files; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->files; + } + + public function count(): int + { + return count($this->files); + } + + public function getIterator(): TestFileCollectionIterator + { + return new TestFileCollectionIterator($this); + } + + public function isEmpty(): bool + { + return $this->count() === 0; + } +} diff --git a/src/TextUI/Configuration/Value/TestFileCollectionIterator.php b/src/TextUI/Configuration/Value/TestFileCollectionIterator.php new file mode 100644 index 00000000000..ed328e9ec36 --- /dev/null +++ b/src/TextUI/Configuration/Value/TestFileCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestFileCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $files; + private int $position = 0; + + public function __construct(TestFileCollection $files) + { + $this->files = $files->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->files); + } + + public function key(): int + { + return $this->position; + } + + public function current(): TestFile + { + return $this->files[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/TestSuite.php b/src/TextUI/Configuration/Value/TestSuite.php new file mode 100644 index 00000000000..fdba72e0bad --- /dev/null +++ b/src/TextUI/Configuration/Value/TestSuite.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TestSuite +{ + /** + * @var non-empty-string + */ + private string $name; + private TestDirectoryCollection $directories; + private TestFileCollection $files; + private FileCollection $exclude; + + /** + * @param non-empty-string $name + */ + public function __construct(string $name, TestDirectoryCollection $directories, TestFileCollection $files, FileCollection $exclude) + { + $this->name = $name; + $this->directories = $directories; + $this->files = $files; + $this->exclude = $exclude; + } + + /** + * @return non-empty-string + */ + public function name(): string + { + return $this->name; + } + + public function directories(): TestDirectoryCollection + { + return $this->directories; + } + + public function files(): TestFileCollection + { + return $this->files; + } + + public function exclude(): FileCollection + { + return $this->exclude; + } +} diff --git a/src/TextUI/Configuration/Value/TestSuiteCollection.php b/src/TextUI/Configuration/Value/TestSuiteCollection.php new file mode 100644 index 00000000000..26c9a645709 --- /dev/null +++ b/src/TextUI/Configuration/Value/TestSuiteCollection.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class TestSuiteCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $testSuites; + + /** + * @param list $testSuites + */ + public static function fromArray(array $testSuites): self + { + return new self(...$testSuites); + } + + private function __construct(TestSuite ...$testSuites) + { + $this->testSuites = $testSuites; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->testSuites; + } + + public function count(): int + { + return count($this->testSuites); + } + + public function getIterator(): TestSuiteCollectionIterator + { + return new TestSuiteCollectionIterator($this); + } + + public function isEmpty(): bool + { + return $this->count() === 0; + } +} diff --git a/src/TextUI/Configuration/Value/TestSuiteCollectionIterator.php b/src/TextUI/Configuration/Value/TestSuiteCollectionIterator.php new file mode 100644 index 00000000000..d0b0768a48d --- /dev/null +++ b/src/TextUI/Configuration/Value/TestSuiteCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class TestSuiteCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $testSuites; + private int $position = 0; + + public function __construct(TestSuiteCollection $testSuites) + { + $this->testSuites = $testSuites->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->testSuites); + } + + public function key(): int + { + return $this->position; + } + + public function current(): TestSuite + { + return $this->testSuites[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Value/Variable.php b/src/TextUI/Configuration/Value/Variable.php new file mode 100644 index 00000000000..cc0425c8c6d --- /dev/null +++ b/src/TextUI/Configuration/Value/Variable.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Variable +{ + private string $name; + private mixed $value; + private bool $force; + + public function __construct(string $name, mixed $value, bool $force) + { + $this->name = $name; + $this->value = $value; + $this->force = $force; + } + + public function name(): string + { + return $this->name; + } + + public function value(): mixed + { + return $this->value; + } + + public function force(): bool + { + return $this->force; + } +} diff --git a/src/TextUI/Configuration/Value/VariableCollection.php b/src/TextUI/Configuration/Value/VariableCollection.php new file mode 100644 index 00000000000..77fb4cff965 --- /dev/null +++ b/src/TextUI/Configuration/Value/VariableCollection.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Countable; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + * + * @template-implements IteratorAggregate + */ +final readonly class VariableCollection implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $variables; + + /** + * @param list $variables + */ + public static function fromArray(array $variables): self + { + return new self(...$variables); + } + + private function __construct(Variable ...$variables) + { + $this->variables = $variables; + } + + /** + * @return list + */ + public function asArray(): array + { + return $this->variables; + } + + public function count(): int + { + return count($this->variables); + } + + public function getIterator(): VariableCollectionIterator + { + return new VariableCollectionIterator($this); + } +} diff --git a/src/TextUI/Configuration/Value/VariableCollectionIterator.php b/src/TextUI/Configuration/Value/VariableCollectionIterator.php new file mode 100644 index 00000000000..2e32194c17c --- /dev/null +++ b/src/TextUI/Configuration/Value/VariableCollectionIterator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function count; +use Iterator; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @template-implements Iterator + */ +final class VariableCollectionIterator implements Iterator +{ + /** + * @var list + */ + private readonly array $variables; + private int $position = 0; + + public function __construct(VariableCollection $variables) + { + $this->variables = $variables->asArray(); + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->variables); + } + + public function key(): int + { + return $this->position; + } + + public function current(): Variable + { + return $this->variables[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php b/src/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php new file mode 100644 index 00000000000..d66f58f1c47 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/CodeCoverage.php @@ -0,0 +1,255 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage; + +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\OpenClover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml; +use PHPUnit\TextUI\XmlConfiguration\Exception; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class CodeCoverage +{ + private bool $pathCoverage; + private bool $includeUncoveredFiles; + private bool $ignoreDeprecatedCodeUnits; + private bool $disableCodeCoverageIgnore; + private ?Clover $clover; + private ?Cobertura $cobertura; + private ?Crap4j $crap4j; + private ?Html $html; + private ?OpenClover $openClover; + private ?Php $php; + private ?Text $text; + private ?Xml $xml; + + public function __construct(bool $pathCoverage, bool $includeUncoveredFiles, bool $ignoreDeprecatedCodeUnits, bool $disableCodeCoverageIgnore, ?Clover $clover, ?Cobertura $cobertura, ?Crap4j $crap4j, ?Html $html, ?OpenClover $openClover, ?Php $php, ?Text $text, ?Xml $xml) + { + $this->pathCoverage = $pathCoverage; + $this->includeUncoveredFiles = $includeUncoveredFiles; + $this->ignoreDeprecatedCodeUnits = $ignoreDeprecatedCodeUnits; + $this->disableCodeCoverageIgnore = $disableCodeCoverageIgnore; + $this->clover = $clover; + $this->cobertura = $cobertura; + $this->crap4j = $crap4j; + $this->html = $html; + $this->openClover = $openClover; + $this->php = $php; + $this->text = $text; + $this->xml = $xml; + } + + public function pathCoverage(): bool + { + return $this->pathCoverage; + } + + public function includeUncoveredFiles(): bool + { + return $this->includeUncoveredFiles; + } + + public function ignoreDeprecatedCodeUnits(): bool + { + return $this->ignoreDeprecatedCodeUnits; + } + + public function disableCodeCoverageIgnore(): bool + { + return $this->disableCodeCoverageIgnore; + } + + /** + * @phpstan-assert-if-true !null $this->clover + */ + public function hasClover(): bool + { + return $this->clover !== null; + } + + /** + * @throws Exception + */ + public function clover(): Clover + { + if (!$this->hasClover()) { + throw new Exception( + 'Code Coverage report "Clover XML" has not been configured', + ); + } + + return $this->clover; + } + + /** + * @phpstan-assert-if-true !null $this->cobertura + */ + public function hasCobertura(): bool + { + return $this->cobertura !== null; + } + + /** + * @throws Exception + */ + public function cobertura(): Cobertura + { + if (!$this->hasCobertura()) { + throw new Exception( + 'Code Coverage report "Cobertura XML" has not been configured', + ); + } + + return $this->cobertura; + } + + /** + * @phpstan-assert-if-true !null $this->crap4j + */ + public function hasCrap4j(): bool + { + return $this->crap4j !== null; + } + + /** + * @throws Exception + */ + public function crap4j(): Crap4j + { + if (!$this->hasCrap4j()) { + throw new Exception( + 'Code Coverage report "Crap4J" has not been configured', + ); + } + + return $this->crap4j; + } + + /** + * @phpstan-assert-if-true !null $this->html + */ + public function hasHtml(): bool + { + return $this->html !== null; + } + + /** + * @throws Exception + */ + public function html(): Html + { + if (!$this->hasHtml()) { + throw new Exception( + 'Code Coverage report "HTML" has not been configured', + ); + } + + return $this->html; + } + + /** + * @phpstan-assert-if-true !null $this->openClover + */ + public function hasOpenClover(): bool + { + return $this->openClover !== null; + } + + /** + * @throws Exception + */ + public function openClover(): OpenClover + { + if (!$this->hasOpenClover()) { + throw new Exception( + 'Code Coverage report "OpenClover XML" has not been configured', + ); + } + + return $this->openClover; + } + + /** + * @phpstan-assert-if-true !null $this->php + */ + public function hasPhp(): bool + { + return $this->php !== null; + } + + /** + * @throws Exception + */ + public function php(): Php + { + if (!$this->hasPhp()) { + throw new Exception( + 'Code Coverage report "PHP" has not been configured', + ); + } + + return $this->php; + } + + /** + * @phpstan-assert-if-true !null $this->text + */ + public function hasText(): bool + { + return $this->text !== null; + } + + /** + * @throws Exception + */ + public function text(): Text + { + if (!$this->hasText()) { + throw new Exception( + 'Code Coverage report "Text" has not been configured', + ); + } + + return $this->text; + } + + /** + * @phpstan-assert-if-true !null $this->xml + */ + public function hasXml(): bool + { + return $this->xml !== null; + } + + /** + * @throws Exception + */ + public function xml(): Xml + { + if (!$this->hasXml()) { + throw new Exception( + 'Code Coverage report "XML" has not been configured', + ); + } + + return $this->xml; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php new file mode 100644 index 00000000000..cdaf122e9c8 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Clover.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Clover +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php new file mode 100644 index 00000000000..015dba39407 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Cobertura.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Cobertura +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.php new file mode 100644 index 00000000000..24aa66ddf98 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Crap4j.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Crap4j +{ + private File $target; + private int $threshold; + + public function __construct(File $target, int $threshold) + { + $this->target = $target; + $this->threshold = $threshold; + } + + public function target(): File + { + return $this->target; + } + + public function threshold(): int + { + return $this->threshold; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php new file mode 100644 index 00000000000..dde8880f129 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Html.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\Directory; +use PHPUnit\TextUI\Configuration\NoCustomCssFileException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Html +{ + private Directory $target; + private int $lowUpperBound; + private int $highLowerBound; + private string $colorSuccessLow; + private string $colorSuccessMedium; + private string $colorSuccessHigh; + private string $colorWarning; + private string $colorDanger; + private ?string $customCssFile; + + public function __construct(Directory $target, int $lowUpperBound, int $highLowerBound, string $colorSuccessLow, string $colorSuccessMedium, string $colorSuccessHigh, string $colorWarning, string $colorDanger, ?string $customCssFile) + { + $this->target = $target; + $this->lowUpperBound = $lowUpperBound; + $this->highLowerBound = $highLowerBound; + $this->colorSuccessLow = $colorSuccessLow; + $this->colorSuccessMedium = $colorSuccessMedium; + $this->colorSuccessHigh = $colorSuccessHigh; + $this->colorWarning = $colorWarning; + $this->colorDanger = $colorDanger; + $this->customCssFile = $customCssFile; + } + + public function target(): Directory + { + return $this->target; + } + + public function lowUpperBound(): int + { + return $this->lowUpperBound; + } + + public function highLowerBound(): int + { + return $this->highLowerBound; + } + + public function colorSuccessLow(): string + { + return $this->colorSuccessLow; + } + + public function colorSuccessMedium(): string + { + return $this->colorSuccessMedium; + } + + public function colorSuccessHigh(): string + { + return $this->colorSuccessHigh; + } + + public function colorWarning(): string + { + return $this->colorWarning; + } + + public function colorDanger(): string + { + return $this->colorDanger; + } + + /** + * @phpstan-assert-if-true !null $this->customCssFile + */ + public function hasCustomCssFile(): bool + { + return $this->customCssFile !== null; + } + + /** + * @throws NoCustomCssFileException + */ + public function customCssFile(): string + { + if (!$this->hasCustomCssFile()) { + throw new NoCustomCssFileException; + } + + return $this->customCssFile; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php new file mode 100644 index 00000000000..e20a24d08cb --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/OpenClover.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class OpenClover +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php new file mode 100644 index 00000000000..ae022e7a018 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Php.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Php +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Text.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Text.php new file mode 100644 index 00000000000..cf04d9101d5 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Text.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Text +{ + private File $target; + private bool $showUncoveredFiles; + private bool $showOnlySummary; + + public function __construct(File $target, bool $showUncoveredFiles, bool $showOnlySummary) + { + $this->target = $target; + $this->showUncoveredFiles = $showUncoveredFiles; + $this->showOnlySummary = $showOnlySummary; + } + + public function target(): File + { + return $this->target; + } + + public function showUncoveredFiles(): bool + { + return $this->showUncoveredFiles; + } + + public function showOnlySummary(): bool + { + return $this->showOnlySummary; + } +} diff --git a/src/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php new file mode 100644 index 00000000000..c67ef1eea02 --- /dev/null +++ b/src/TextUI/Configuration/Xml/CodeCoverage/Report/Xml.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report; + +use PHPUnit\TextUI\Configuration\Directory; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Xml +{ + private Directory $target; + private bool $includeSource; + + public function __construct(Directory $target, bool $includeSource) + { + $this->target = $target; + $this->includeSource = $includeSource; + } + + public function target(): Directory + { + return $this->target; + } + + public function includeSource(): bool + { + return $this->includeSource; + } +} diff --git a/src/TextUI/Configuration/Xml/Configuration.php b/src/TextUI/Configuration/Xml/Configuration.php new file mode 100644 index 00000000000..378022b0be1 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Configuration.php @@ -0,0 +1,104 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class Configuration +{ + private ExtensionBootstrapCollection $extensions; + private Source $source; + private CodeCoverage $codeCoverage; + private Groups $groups; + private Logging $logging; + private Php $php; + private PHPUnit $phpunit; + private TestSuiteCollection $testSuite; + + public function __construct(ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, Groups $groups, Logging $logging, Php $php, PHPUnit $phpunit, TestSuiteCollection $testSuite) + { + $this->extensions = $extensions; + $this->source = $source; + $this->codeCoverage = $codeCoverage; + $this->groups = $groups; + $this->logging = $logging; + $this->php = $php; + $this->phpunit = $phpunit; + $this->testSuite = $testSuite; + } + + public function extensions(): ExtensionBootstrapCollection + { + return $this->extensions; + } + + public function source(): Source + { + return $this->source; + } + + public function codeCoverage(): CodeCoverage + { + return $this->codeCoverage; + } + + public function groups(): Groups + { + return $this->groups; + } + + public function logging(): Logging + { + return $this->logging; + } + + public function php(): Php + { + return $this->php; + } + + public function phpunit(): PHPUnit + { + return $this->phpunit; + } + + public function testSuite(): TestSuiteCollection + { + return $this->testSuite; + } + + /** + * @phpstan-assert-if-true DefaultConfiguration $this + */ + public function isDefault(): bool + { + return false; + } + + /** + * @phpstan-assert-if-true LoadedFromFileConfiguration $this + */ + public function wasLoadedFromFile(): bool + { + return false; + } +} diff --git a/src/TextUI/Configuration/Xml/DefaultConfiguration.php b/src/TextUI/Configuration/Xml/DefaultConfiguration.php new file mode 100644 index 00000000000..de16474a8f5 --- /dev/null +++ b/src/TextUI/Configuration/Xml/DefaultConfiguration.php @@ -0,0 +1,172 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\Configuration\ConstantCollection; +use PHPUnit\TextUI\Configuration\DirectoryCollection; +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\FileCollection; +use PHPUnit\TextUI\Configuration\FilterDirectoryCollection as CodeCoverageFilterDirectoryCollection; +use PHPUnit\TextUI\Configuration\GroupCollection; +use PHPUnit\TextUI\Configuration\IniSettingCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\Configuration\VariableCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class DefaultConfiguration extends Configuration +{ + public static function create(): self + { + return new self( + ExtensionBootstrapCollection::fromArray([]), + new Source( + null, + false, + CodeCoverageFilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + CodeCoverageFilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ), + new CodeCoverage( + false, + true, + false, + false, + null, + null, + null, + null, + null, + null, + null, + null, + ), + new Groups( + GroupCollection::fromArray([]), + GroupCollection::fromArray([]), + ), + new Logging( + null, + null, + null, + null, + null, + ), + new Php( + DirectoryCollection::fromArray([]), + IniSettingCollection::fromArray([]), + ConstantCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + VariableCollection::fromArray([]), + ), + new PHPUnit( + null, + true, + 80, + \PHPUnit\TextUI\Configuration\Configuration::COLOR_DEFAULT, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + null, + [], + false, + false, + false, + false, + false, + true, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + false, + null, + false, + false, + true, + false, + false, + 1, + 1, + 10, + 60, + null, + TestSuiteSorter::ORDER_DEFAULT, + true, + false, + false, + false, + false, + false, + false, + 100, + 10, + ), + TestSuiteCollection::fromArray([]), + ); + } + + public function isDefault(): bool + { + return true; + } +} diff --git a/src/TextUI/Configuration/Xml/Exception.php b/src/TextUI/Configuration/Xml/Exception.php new file mode 100644 index 00000000000..60c3c9acc71 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Exception extends RuntimeException implements \PHPUnit\Exception +{ +} diff --git a/src/TextUI/Configuration/Xml/Generator.php b/src/TextUI/Configuration/Xml/Generator.php new file mode 100644 index 00000000000..4fc4ca2e69b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Generator.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function str_replace; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Generator +{ + /** + * @var string + */ + private const string TEMPLATE = <<<'EOT' + + + + + {tests_directory} + + + + + + {src_directory} + + + + +EOT; + + public function generateDefaultConfiguration(string $schemaLocation, string $bootstrapScript, string $testsDirectory, string $srcDirectory, string $cacheDirectory): string + { + return str_replace( + [ + '{schema_location}', + '{bootstrap_script}', + '{tests_directory}', + '{src_directory}', + '{cache_directory}', + ], + [ + $schemaLocation, + $bootstrapScript, + $testsDirectory, + $srcDirectory, + $cacheDirectory, + ], + self::TEMPLATE, + ); + } +} diff --git a/src/TextUI/Configuration/Xml/Groups.php b/src/TextUI/Configuration/Xml/Groups.php new file mode 100644 index 00000000000..1a7cc6b453f --- /dev/null +++ b/src/TextUI/Configuration/Xml/Groups.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\GroupCollection; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Groups +{ + private GroupCollection $include; + private GroupCollection $exclude; + + public function __construct(GroupCollection $include, GroupCollection $exclude) + { + $this->include = $include; + $this->exclude = $exclude; + } + + public function hasInclude(): bool + { + return !$this->include->isEmpty(); + } + + public function include(): GroupCollection + { + return $this->include; + } + + public function hasExclude(): bool + { + return !$this->exclude->isEmpty(); + } + + public function exclude(): GroupCollection + { + return $this->exclude; + } +} diff --git a/src/TextUI/Configuration/Xml/LoadedFromFileConfiguration.php b/src/TextUI/Configuration/Xml/LoadedFromFileConfiguration.php new file mode 100644 index 00000000000..e69d137fe2c --- /dev/null +++ b/src/TextUI/Configuration/Xml/LoadedFromFileConfiguration.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class LoadedFromFileConfiguration extends Configuration +{ + /** + * @var non-empty-string + */ + private string $filename; + private ValidationResult $validationResult; + + /** + * @param non-empty-string $filename + */ + public function __construct(string $filename, ValidationResult $validationResult, ExtensionBootstrapCollection $extensions, Source $source, CodeCoverage $codeCoverage, Groups $groups, Logging $logging, Php $php, PHPUnit $phpunit, TestSuiteCollection $testSuite) + { + $this->filename = $filename; + $this->validationResult = $validationResult; + + parent::__construct( + $extensions, + $source, + $codeCoverage, + $groups, + $logging, + $php, + $phpunit, + $testSuite, + ); + } + + /** + * @return non-empty-string + */ + public function filename(): string + { + return $this->filename; + } + + public function hasValidationErrors(): bool + { + return $this->validationResult->hasValidationErrors(); + } + + public function validationErrors(): string + { + return $this->validationResult->asString(); + } + + public function wasLoadedFromFile(): bool + { + return true; + } +} diff --git a/src/TextUI/Configuration/Xml/Loader.php b/src/TextUI/Configuration/Xml/Loader.php new file mode 100644 index 00000000000..ca7a3557d62 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Loader.php @@ -0,0 +1,1226 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use const PHP_VERSION; +use function assert; +use function defined; +use function dirname; +use function explode; +use function is_numeric; +use function preg_match; +use function realpath; +use function sprintf; +use function str_contains; +use function str_starts_with; +use function strlen; +use function strtolower; +use function substr; +use function trim; +use DOMDocument; +use DOMElement; +use DOMNode; +use DOMNodeList; +use DOMXPath; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\Runner\Version; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Constant; +use PHPUnit\TextUI\Configuration\ConstantCollection; +use PHPUnit\TextUI\Configuration\Directory; +use PHPUnit\TextUI\Configuration\DirectoryCollection; +use PHPUnit\TextUI\Configuration\ExtensionBootstrap; +use PHPUnit\TextUI\Configuration\ExtensionBootstrapCollection; +use PHPUnit\TextUI\Configuration\File; +use PHPUnit\TextUI\Configuration\FileCollection; +use PHPUnit\TextUI\Configuration\FilterDirectory; +use PHPUnit\TextUI\Configuration\FilterDirectoryCollection; +use PHPUnit\TextUI\Configuration\Group; +use PHPUnit\TextUI\Configuration\GroupCollection; +use PHPUnit\TextUI\Configuration\IniSetting; +use PHPUnit\TextUI\Configuration\IniSettingCollection; +use PHPUnit\TextUI\Configuration\Php; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\TestDirectory; +use PHPUnit\TextUI\Configuration\TestDirectoryCollection; +use PHPUnit\TextUI\Configuration\TestFile; +use PHPUnit\TextUI\Configuration\TestFileCollection; +use PHPUnit\TextUI\Configuration\TestSuite as TestSuiteConfiguration; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\Configuration\Variable; +use PHPUnit\TextUI\Configuration\VariableCollection; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\CodeCoverage; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Clover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Cobertura; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Crap4j; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Html as CodeCoverageHtml; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\OpenClover; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Php as CodeCoveragePhp; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Text as CodeCoverageText; +use PHPUnit\TextUI\XmlConfiguration\CodeCoverage\Report\Xml as CodeCoverageXml; +use PHPUnit\TextUI\XmlConfiguration\Logging\Junit; +use PHPUnit\TextUI\XmlConfiguration\Logging\Logging; +use PHPUnit\TextUI\XmlConfiguration\Logging\Otr; +use PHPUnit\TextUI\XmlConfiguration\Logging\TeamCity; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; +use PHPUnit\Util\VersionComparisonOperator; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; +use SebastianBergmann\CodeCoverage\Report\Html\Colors; +use SebastianBergmann\CodeCoverage\Report\Thresholds; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loader +{ + /** + * @throws Exception + */ + public function load(string $filename): LoadedFromFileConfiguration + { + try { + $document = (new XmlLoader)->loadFile($filename); + } catch (XmlException $e) { + throw new Exception( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + + $xpath = new DOMXPath($document); + + try { + $xsdFilename = (new SchemaFinder)->find(Version::series()); + } catch (CannotFindSchemaException $e) { + throw new Exception( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + + $configurationFileRealpath = realpath($filename); + + assert($configurationFileRealpath !== false && $configurationFileRealpath !== ''); + + $validationResult = (new Validator)->validate($document, $xsdFilename); + + try { + return new LoadedFromFileConfiguration( + $configurationFileRealpath, + $validationResult, + $this->extensions($xpath), + $this->source($configurationFileRealpath, $xpath), + $this->codeCoverage($configurationFileRealpath, $xpath), + $this->groups($xpath), + $this->logging($configurationFileRealpath, $xpath), + $this->php($configurationFileRealpath, $xpath), + $this->phpunit($configurationFileRealpath, $document, $xpath), + $this->testSuite($configurationFileRealpath, $xpath), + ); + } catch (Throwable $t) { + $message = sprintf( + 'Cannot load XML configuration file %s', + $configurationFileRealpath, + ); + + if ($validationResult->hasValidationErrors()) { + $message .= ' because it has validation errors:' . PHP_EOL . $validationResult->asString(); + } + + throw new Exception($message, previous: $t); + } + } + + private function logging(string $filename, DOMXPath $xpath): Logging + { + $junit = null; + $element = $this->element($xpath, 'logging/junit'); + + if ($element !== null) { + $junit = new Junit( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $otr = null; + $element = $this->element($xpath, 'logging/otr'); + + if ($element !== null) { + $otr = new Otr( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + $this->parseBooleanAttribute($element, 'includeGitInformation', false), + ); + } + + $teamCity = null; + $element = $this->element($xpath, 'logging/teamcity'); + + if ($element !== null) { + $teamCity = new TeamCity( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $testDoxHtml = null; + $element = $this->element($xpath, 'logging/testdoxHtml'); + + if ($element !== null) { + $testDoxHtml = new TestDoxHtml( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $testDoxText = null; + $element = $this->element($xpath, 'logging/testdoxText'); + + if ($element !== null) { + $testDoxText = new TestDoxText( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + return new Logging( + $junit, + $otr, + $teamCity, + $testDoxHtml, + $testDoxText, + ); + } + + private function extensions(DOMXPath $xpath): ExtensionBootstrapCollection + { + $extensionBootstrappers = []; + + $bootstrapNodes = $xpath->query('extensions/bootstrap'); + + assert($bootstrapNodes instanceof DOMNodeList); + + foreach ($bootstrapNodes as $bootstrap) { + assert($bootstrap instanceof DOMElement); + + $parameters = []; + + $parameterNodes = $xpath->query('parameter', $bootstrap); + + assert($parameterNodes instanceof DOMNodeList); + + foreach ($parameterNodes as $parameter) { + assert($parameter instanceof DOMElement); + + $parameters[$parameter->getAttribute('name')] = $parameter->getAttribute('value'); + } + + $className = $bootstrap->getAttribute('class'); + + assert($className !== ''); + + $extensionBootstrappers[] = new ExtensionBootstrap( + $className, + $parameters, + ); + } + + return ExtensionBootstrapCollection::fromArray($extensionBootstrappers); + } + + /** + * @return non-empty-string + */ + private function toAbsolutePath(string $filename, string $path): string + { + $path = trim($path); + + if (str_starts_with($path, '/')) { + return $path; + } + + // Matches the following on Windows: + // - \\NetworkComputer\Path + // - \\.\D: + // - \\.\c: + // - C:\Windows + // - C:\windows + // - C:/windows + // - c:/windows + if (defined('PHP_WINDOWS_VERSION_BUILD') && + $path !== '' && + ($path[0] === '\\' || (strlen($path) >= 3 && preg_match('#^[A-Z]:[/\\\]#i', substr($path, 0, 3))))) { + return $path; + } + + if (str_contains($path, '://')) { + return $path; + } + + return dirname($filename) . DIRECTORY_SEPARATOR . $path; + } + + private function source(string $filename, DOMXPath $xpath): Source + { + $baseline = null; + $restrictNotices = false; + $restrictWarnings = false; + $ignoreSuppressionOfDeprecations = false; + $ignoreSuppressionOfPhpDeprecations = false; + $ignoreSuppressionOfErrors = false; + $ignoreSuppressionOfNotices = false; + $ignoreSuppressionOfPhpNotices = false; + $ignoreSuppressionOfWarnings = false; + $ignoreSuppressionOfPhpWarnings = false; + $ignoreSelfDeprecations = false; + $ignoreDirectDeprecations = false; + $ignoreIndirectDeprecations = false; + + $element = $this->element($xpath, 'source'); + + if ($element !== null) { + $baseline = $this->parseStringAttribute($element, 'baseline'); + + if ($baseline !== null) { + $baseline = $this->toAbsolutePath($filename, $baseline); + } + + $restrictNotices = $this->parseBooleanAttribute($element, 'restrictNotices', false); + $restrictWarnings = $this->parseBooleanAttribute($element, 'restrictWarnings', false); + $ignoreSuppressionOfDeprecations = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfDeprecations', false); + $ignoreSuppressionOfPhpDeprecations = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpDeprecations', false); + $ignoreSuppressionOfErrors = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfErrors', false); + $ignoreSuppressionOfNotices = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfNotices', false); + $ignoreSuppressionOfPhpNotices = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpNotices', false); + $ignoreSuppressionOfWarnings = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfWarnings', false); + $ignoreSuppressionOfPhpWarnings = $this->parseBooleanAttribute($element, 'ignoreSuppressionOfPhpWarnings', false); + $ignoreSelfDeprecations = $this->parseBooleanAttribute($element, 'ignoreSelfDeprecations', false); + $ignoreDirectDeprecations = $this->parseBooleanAttribute($element, 'ignoreDirectDeprecations', false); + $ignoreIndirectDeprecations = $this->parseBooleanAttribute($element, 'ignoreIndirectDeprecations', false); + } + + $deprecationTriggers = [ + 'functions' => [], + 'methods' => [], + ]; + + $functionNodes = $xpath->query('source/deprecationTrigger/function'); + + assert($functionNodes instanceof DOMNodeList); + + foreach ($functionNodes as $functionNode) { + assert($functionNode instanceof DOMElement); + + $deprecationTriggers['functions'][] = $functionNode->textContent; + } + + $methodNodes = $xpath->query('source/deprecationTrigger/method'); + + assert($methodNodes instanceof DOMNodeList); + + foreach ($methodNodes as $methodNode) { + assert($methodNode instanceof DOMElement); + + $deprecationTriggers['methods'][] = $methodNode->textContent; + } + + return new Source( + $baseline, + false, + $this->readFilterDirectories($filename, $xpath, 'source/include/directory'), + $this->readFilterFiles($filename, $xpath, 'source/include/file'), + $this->readFilterDirectories($filename, $xpath, 'source/exclude/directory'), + $this->readFilterFiles($filename, $xpath, 'source/exclude/file'), + $restrictNotices, + $restrictWarnings, + $ignoreSuppressionOfDeprecations, + $ignoreSuppressionOfPhpDeprecations, + $ignoreSuppressionOfErrors, + $ignoreSuppressionOfNotices, + $ignoreSuppressionOfPhpNotices, + $ignoreSuppressionOfWarnings, + $ignoreSuppressionOfPhpWarnings, + $deprecationTriggers, + $ignoreSelfDeprecations, + $ignoreDirectDeprecations, + $ignoreIndirectDeprecations, + ); + } + + private function codeCoverage(string $filename, DOMXPath $xpath): CodeCoverage + { + $pathCoverage = false; + $includeUncoveredFiles = true; + $ignoreDeprecatedCodeUnits = false; + $disableCodeCoverageIgnore = false; + + $element = $this->element($xpath, 'coverage'); + + if ($element !== null) { + $pathCoverage = $this->parseBooleanAttribute( + $element, + 'pathCoverage', + false, + ); + + $includeUncoveredFiles = $this->parseBooleanAttribute( + $element, + 'includeUncoveredFiles', + true, + ); + + $ignoreDeprecatedCodeUnits = $this->parseBooleanAttribute( + $element, + 'ignoreDeprecatedCodeUnits', + false, + ); + + $disableCodeCoverageIgnore = $this->parseBooleanAttribute( + $element, + 'disableCodeCoverageIgnore', + false, + ); + } + + $clover = null; + $element = $this->element($xpath, 'coverage/report/clover'); + + if ($element !== null) { + $clover = new Clover( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $cobertura = null; + $element = $this->element($xpath, 'coverage/report/cobertura'); + + if ($element !== null) { + $cobertura = new Cobertura( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $crap4j = null; + $element = $this->element($xpath, 'coverage/report/crap4j'); + + if ($element !== null) { + $crap4j = new Crap4j( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + $this->parseIntegerAttribute($element, 'threshold', 30), + ); + } + + $html = null; + $element = $this->element($xpath, 'coverage/report/html'); + + if ($element !== null) { + $defaultColors = Colors::default(); + $defaultThresholds = Thresholds::default(); + + $html = new CodeCoverageHtml( + new Directory( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputDirectory'), + ), + ), + $this->parseIntegerAttribute($element, 'lowUpperBound', $defaultThresholds->lowUpperBound()), + $this->parseIntegerAttribute($element, 'highLowerBound', $defaultThresholds->highLowerBound()), + $this->parseStringAttributeWithDefault($element, 'colorSuccessLow', $defaultColors->successLow()), + $this->parseStringAttributeWithDefault($element, 'colorSuccessMedium', $defaultColors->successMedium()), + $this->parseStringAttributeWithDefault($element, 'colorSuccessHigh', $defaultColors->successHigh()), + $this->parseStringAttributeWithDefault($element, 'colorWarning', $defaultColors->warning()), + $this->parseStringAttributeWithDefault($element, 'colorDanger', $defaultColors->danger()), + $this->parseStringAttribute($element, 'customCssFile'), + ); + } + + $openClover = null; + $element = $this->element($xpath, 'coverage/report/openclover'); + + if ($element !== null) { + $openClover = new OpenClover( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $php = null; + $element = $this->element($xpath, 'coverage/report/php'); + + if ($element !== null) { + $php = new CodeCoveragePhp( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + ); + } + + $text = null; + $element = $this->element($xpath, 'coverage/report/text'); + + if ($element !== null) { + $text = new CodeCoverageText( + new File( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputFile'), + ), + ), + $this->parseBooleanAttribute($element, 'showUncoveredFiles', false), + $this->parseBooleanAttribute($element, 'showOnlySummary', false), + ); + } + + $xml = null; + $element = $this->element($xpath, 'coverage/report/xml'); + + if ($element !== null) { + $xml = new CodeCoverageXml( + new Directory( + $this->toAbsolutePath( + $filename, + (string) $this->parseStringAttribute($element, 'outputDirectory'), + ), + ), + $this->parseBooleanAttribute($element, 'includeSource', true), + ); + } + + return new CodeCoverage( + $pathCoverage, + $includeUncoveredFiles, + $ignoreDeprecatedCodeUnits, + $disableCodeCoverageIgnore, + $clover, + $cobertura, + $crap4j, + $html, + $openClover, + $php, + $text, + $xml, + ); + } + + private function booleanFromString(string $value, bool $default): bool + { + if (strtolower($value) === 'false') { + return false; + } + + if (strtolower($value) === 'true') { + return true; + } + + return $default; + } + + private function valueFromString(string $value): bool|string + { + if (strtolower($value) === 'false') { + return false; + } + + if (strtolower($value) === 'true') { + return true; + } + + return $value; + } + + private function readFilterDirectories(string $filename, DOMXPath $xpath, string $query): FilterDirectoryCollection + { + $directories = []; + + $directoryNodes = $xpath->query($query); + + assert($directoryNodes instanceof DOMNodeList); + + foreach ($directoryNodes as $directoryNode) { + assert($directoryNode instanceof DOMElement); + + $directoryPath = $directoryNode->textContent; + + if ($directoryPath === '') { + continue; + } + + $directories[] = new FilterDirectory( + $this->toAbsolutePath($filename, $directoryPath), + $directoryNode->hasAttribute('prefix') ? $directoryNode->getAttribute('prefix') : '', + $directoryNode->hasAttribute('suffix') ? $directoryNode->getAttribute('suffix') : '.php', + ); + } + + return FilterDirectoryCollection::fromArray($directories); + } + + private function readFilterFiles(string $filename, DOMXPath $xpath, string $query): FileCollection + { + $files = []; + + $fileNodes = $xpath->query($query); + + assert($fileNodes instanceof DOMNodeList); + + foreach ($fileNodes as $fileNode) { + assert($fileNode instanceof DOMNode); + + $filePath = $fileNode->textContent; + + if ($filePath !== '') { + $files[] = new File($this->toAbsolutePath($filename, $filePath)); + } + } + + return FileCollection::fromArray($files); + } + + private function groups(DOMXPath $xpath): Groups + { + $include = []; + $exclude = []; + + $groupNodes = $xpath->query('groups/include/group'); + + assert($groupNodes instanceof DOMNodeList); + + foreach ($groupNodes as $groupNode) { + assert($groupNode instanceof DOMNode); + + $include[] = new Group($groupNode->textContent); + } + + $groupNodes = $xpath->query('groups/exclude/group'); + + assert($groupNodes instanceof DOMNodeList); + + foreach ($groupNodes as $groupNode) { + assert($groupNode instanceof DOMNode); + + $exclude[] = new Group($groupNode->textContent); + } + + return new Groups( + GroupCollection::fromArray($include), + GroupCollection::fromArray($exclude), + ); + } + + private function parseBooleanAttribute(DOMElement $element, string $attribute, bool $default): bool + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + + return $this->booleanFromString( + $element->getAttribute($attribute), + false, + ); + } + + private function parseIntegerAttribute(DOMElement $element, string $attribute, int $default): int + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + + return $this->parseInteger( + $element->getAttribute($attribute), + $default, + ); + } + + private function parseStringAttribute(DOMElement $element, string $attribute): ?string + { + if (!$element->hasAttribute($attribute)) { + return null; + } + + return $element->getAttribute($attribute); + } + + private function parseStringAttributeWithDefault(DOMElement $element, string $attribute, string $default): string + { + if (!$element->hasAttribute($attribute)) { + return $default; + } + + return $element->getAttribute($attribute); + } + + private function parseInteger(string $value, int $default): int + { + if (is_numeric($value)) { + return (int) $value; + } + + return $default; + } + + private function php(string $filename, DOMXPath $xpath): Php + { + $includePaths = []; + + $includePathNodes = $xpath->query('php/includePath'); + + assert($includePathNodes instanceof DOMNodeList); + + foreach ($includePathNodes as $includePath) { + assert($includePath instanceof DOMNode); + + $path = $includePath->textContent; + + if ($path !== '') { + $includePaths[] = new Directory($this->toAbsolutePath($filename, $path)); + } + } + + $iniSettings = []; + + $iniNodes = $xpath->query('php/ini'); + + assert($iniNodes instanceof DOMNodeList); + + foreach ($iniNodes as $ini) { + assert($ini instanceof DOMElement); + + $iniSettings[] = new IniSetting( + $ini->getAttribute('name'), + $ini->getAttribute('value'), + ); + } + + $constants = []; + + $constNodes = $xpath->query('php/const'); + + assert($constNodes instanceof DOMNodeList); + + foreach ($constNodes as $constNode) { + assert($constNode instanceof DOMElement); + + $value = $constNode->getAttribute('value'); + + $constants[] = new Constant( + $constNode->getAttribute('name'), + $this->valueFromString($value), + ); + } + + $variables = [ + 'var' => [], + 'env' => [], + 'post' => [], + 'get' => [], + 'cookie' => [], + 'server' => [], + 'files' => [], + 'request' => [], + ]; + + foreach (['var', 'env', 'post', 'get', 'cookie', 'server', 'files', 'request'] as $array) { + $varNodes = $xpath->query('php/' . $array); + + assert($varNodes instanceof DOMNodeList); + + foreach ($varNodes as $var) { + assert($var instanceof DOMElement); + + $name = $var->getAttribute('name'); + $value = $var->getAttribute('value'); + $force = false; + $verbatim = false; + + if ($var->hasAttribute('force')) { + $force = $this->booleanFromString($var->getAttribute('force'), false); + } + + if ($var->hasAttribute('verbatim')) { + $verbatim = $this->booleanFromString($var->getAttribute('verbatim'), false); + } + + if (!$verbatim) { + $value = $this->valueFromString($value); + } + + $variables[$array][] = new Variable($name, $value, $force); + } + } + + return new Php( + DirectoryCollection::fromArray($includePaths), + IniSettingCollection::fromArray($iniSettings), + ConstantCollection::fromArray($constants), + VariableCollection::fromArray($variables['var']), + VariableCollection::fromArray($variables['env']), + VariableCollection::fromArray($variables['post']), + VariableCollection::fromArray($variables['get']), + VariableCollection::fromArray($variables['cookie']), + VariableCollection::fromArray($variables['server']), + VariableCollection::fromArray($variables['files']), + VariableCollection::fromArray($variables['request']), + ); + } + + private function phpunit(string $filename, DOMDocument $document, DOMXPath $xpath): PHPUnit + { + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $defectsFirst = false; + $resolveDependencies = $this->parseBooleanAttribute($document->documentElement, 'resolveDependencies', true); + + if ($document->documentElement->hasAttribute('executionOrder')) { + foreach (explode(',', $document->documentElement->getAttribute('executionOrder')) as $order) { + switch ($order) { + case 'default': + $executionOrder = TestSuiteSorter::ORDER_DEFAULT; + $defectsFirst = false; + $resolveDependencies = true; + + break; + + case 'depends': + $resolveDependencies = true; + + break; + + case 'no-depends': + $resolveDependencies = false; + + break; + + case 'defects': + $defectsFirst = true; + + break; + + case 'duration': + $executionOrder = TestSuiteSorter::ORDER_DURATION; + + break; + + case 'random': + $executionOrder = TestSuiteSorter::ORDER_RANDOMIZED; + + break; + + case 'reverse': + $executionOrder = TestSuiteSorter::ORDER_REVERSED; + + break; + + case 'size': + $executionOrder = TestSuiteSorter::ORDER_SIZE; + + break; + } + } + } + + $cacheDirectory = $this->parseStringAttribute($document->documentElement, 'cacheDirectory'); + + if ($cacheDirectory !== null) { + $cacheDirectory = $this->toAbsolutePath($filename, $cacheDirectory); + } + + $bootstrap = $this->parseStringAttribute($document->documentElement, 'bootstrap'); + + if ($bootstrap !== null) { + $bootstrap = $this->toAbsolutePath($filename, $bootstrap); + } + + $extensionsDirectory = $this->parseStringAttribute($document->documentElement, 'extensionsDirectory'); + + if ($extensionsDirectory !== null) { + $extensionsDirectory = $this->toAbsolutePath($filename, $extensionsDirectory); + } + + $backupStaticProperties = false; + + if ($document->documentElement->hasAttribute('backupStaticProperties')) { + $backupStaticProperties = $this->parseBooleanAttribute($document->documentElement, 'backupStaticProperties', false); + } + + $requireCoverageMetadata = false; + + if ($document->documentElement->hasAttribute('requireCoverageMetadata')) { + $requireCoverageMetadata = $this->parseBooleanAttribute($document->documentElement, 'requireCoverageMetadata', false); + } + + $beStrictAboutCoverageMetadata = false; + + if ($document->documentElement->hasAttribute('beStrictAboutCoverageMetadata')) { + $beStrictAboutCoverageMetadata = $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutCoverageMetadata', false); + } + + $shortenArraysForExportThreshold = $this->parseIntegerAttribute($document->documentElement, 'shortenArraysForExportThreshold', 10); + + if ($shortenArraysForExportThreshold < 0) { + $shortenArraysForExportThreshold = 0; + } + + return new PHPUnit( + $cacheDirectory, + $this->parseBooleanAttribute($document->documentElement, 'cacheResult', true), + $this->parseColumns($document), + $this->parseColors($document), + $this->parseBooleanAttribute($document->documentElement, 'stderr', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnAllIssues', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnIncompleteTests', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnSkippedTests', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerDeprecations', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnPhpunitDeprecations', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnPhpunitNotices', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerErrors', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerNotices', false), + $this->parseBooleanAttribute($document->documentElement, 'displayDetailsOnTestsThatTriggerWarnings', false), + $this->parseBooleanAttribute($document->documentElement, 'reverseDefectList', false), + $requireCoverageMetadata, + $bootstrap, + $this->bootstrapForTestSuite($filename, $xpath), + $this->parseBooleanAttribute($document->documentElement, 'processIsolation', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnAllIssues', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnDeprecation', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitDeprecation', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitNotice', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnPhpunitWarning', true), + $this->parseBooleanAttribute($document->documentElement, 'failOnEmptyTestSuite', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnIncomplete', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnNotice', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnRisky', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnSkipped', false), + $this->parseBooleanAttribute($document->documentElement, 'failOnWarning', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnDefect', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnDeprecation', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnError', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnFailure', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnIncomplete', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnNotice', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnRisky', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnSkipped', false), + $this->parseBooleanAttribute($document->documentElement, 'stopOnWarning', false), + $extensionsDirectory, + $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutChangesToGlobalState', false), + $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutOutputDuringTests', false), + $this->parseBooleanAttribute($document->documentElement, 'beStrictAboutTestsThatDoNotTestAnything', true), + $beStrictAboutCoverageMetadata, + $this->parseBooleanAttribute($document->documentElement, 'enforceTimeLimit', false), + $this->parseIntegerAttribute($document->documentElement, 'defaultTimeLimit', 1), + $this->parseIntegerAttribute($document->documentElement, 'timeoutForSmallTests', 1), + $this->parseIntegerAttribute($document->documentElement, 'timeoutForMediumTests', 10), + $this->parseIntegerAttribute($document->documentElement, 'timeoutForLargeTests', 60), + $this->parseStringAttribute($document->documentElement, 'defaultTestSuite'), + $executionOrder, + $resolveDependencies, + $defectsFirst, + $this->parseBooleanAttribute($document->documentElement, 'backupGlobals', false), + $backupStaticProperties, + $this->parseBooleanAttribute($document->documentElement, 'testdox', false), + $this->parseBooleanAttribute($document->documentElement, 'testdoxSummary', false), + $this->parseBooleanAttribute($document->documentElement, 'controlGarbageCollector', false), + $this->parseIntegerAttribute($document->documentElement, 'numberOfTestsBeforeGarbageCollection', 100), + $shortenArraysForExportThreshold, + ); + } + + private function parseColors(DOMDocument $document): string + { + $colors = Configuration::COLOR_DEFAULT; + + if ($document->documentElement->hasAttribute('colors')) { + /* only allow boolean for compatibility with previous versions + 'always' only allowed from command line */ + if ($this->booleanFromString($document->documentElement->getAttribute('colors'), false)) { + $colors = Configuration::COLOR_AUTO; + } else { + $colors = Configuration::COLOR_NEVER; + } + } + + return $colors; + } + + private function parseColumns(DOMDocument $document): int|string + { + $columns = 80; + + if ($document->documentElement->hasAttribute('columns')) { + $columns = $document->documentElement->getAttribute('columns'); + + if ($columns !== 'max') { + $columns = $this->parseInteger($columns, 80); + } + } + + return $columns; + } + + /** + * @return array + */ + private function bootstrapForTestSuite(string $filename, DOMXPath $xpath): array + { + $bootstrapForTestSuite = []; + + foreach ($this->parseTestSuiteElements($xpath) as $element) { + if (!$element->hasAttribute('bootstrap')) { + continue; + } + + $name = $element->getAttribute('name'); + $bootstrap = $element->getAttribute('bootstrap'); + + assert($name !== ''); + assert($bootstrap !== ''); + + $bootstrapForTestSuite[$name] = $this->toAbsolutePath($filename, $bootstrap); + } + + return $bootstrapForTestSuite; + } + + private function testSuite(string $filename, DOMXPath $xpath): TestSuiteCollection + { + $testSuites = []; + + foreach ($this->parseTestSuiteElements($xpath) as $element) { + $exclude = []; + + foreach ($element->getElementsByTagName('exclude') as $excludeNode) { + $excludeFile = $excludeNode->textContent; + + if ($excludeFile !== '') { + $exclude[] = new File($this->toAbsolutePath($filename, $excludeFile)); + } + } + + $directories = []; + + foreach ($element->getElementsByTagName('directory') as $directoryNode) { + assert($directoryNode instanceof DOMElement); + + $directory = $directoryNode->textContent; + + if ($directory === '') { + continue; + } + + $prefix = ''; + + if ($directoryNode->hasAttribute('prefix')) { + $prefix = $directoryNode->getAttribute('prefix'); + } + + $suffix = 'Test.php'; + + if ($directoryNode->hasAttribute('suffix')) { + $suffix = $directoryNode->getAttribute('suffix'); + } + + $phpVersion = PHP_VERSION; + + if ($directoryNode->hasAttribute('phpVersion')) { + $phpVersion = $directoryNode->getAttribute('phpVersion'); + } + + $phpVersionOperator = new VersionComparisonOperator('>='); + + if ($directoryNode->hasAttribute('phpVersionOperator')) { + $phpVersionOperator = new VersionComparisonOperator($directoryNode->getAttribute('phpVersionOperator')); + } + + $groups = []; + + if ($directoryNode->hasAttribute('groups')) { + foreach (explode(',', $directoryNode->getAttribute('groups')) as $group) { + $group = trim($group); + + if ($group === '') { + continue; + } + + $groups[] = $group; + } + } + + $directories[] = new TestDirectory( + $this->toAbsolutePath($filename, $directory), + $prefix, + $suffix, + $phpVersion, + $phpVersionOperator, + $groups, + ); + } + + $files = []; + + foreach ($element->getElementsByTagName('file') as $fileNode) { + assert($fileNode instanceof DOMElement); + + $file = $fileNode->textContent; + + if ($file === '') { + continue; + } + + $phpVersion = PHP_VERSION; + + if ($fileNode->hasAttribute('phpVersion')) { + $phpVersion = $fileNode->getAttribute('phpVersion'); + } + + $phpVersionOperator = new VersionComparisonOperator('>='); + + if ($fileNode->hasAttribute('phpVersionOperator')) { + $phpVersionOperator = new VersionComparisonOperator($fileNode->getAttribute('phpVersionOperator')); + } + + $groups = []; + + if ($fileNode->hasAttribute('groups')) { + foreach (explode(',', $fileNode->getAttribute('groups')) as $group) { + $group = trim($group); + + if ($group === '') { + continue; + } + + $groups[] = $group; + } + } + + $files[] = new TestFile( + $this->toAbsolutePath($filename, $file), + $phpVersion, + $phpVersionOperator, + $groups, + ); + } + + $name = $element->getAttribute('name'); + + assert($name !== ''); + + $testSuites[] = new TestSuiteConfiguration( + $name, + TestDirectoryCollection::fromArray($directories), + TestFileCollection::fromArray($files), + FileCollection::fromArray($exclude), + ); + } + + return TestSuiteCollection::fromArray($testSuites); + } + + /** + * @return list + */ + private function parseTestSuiteElements(DOMXPath $xpath): array + { + $elements = []; + + $testSuiteNodes = $xpath->query('testsuites/testsuite'); + + assert($testSuiteNodes instanceof DOMNodeList); + + if ($testSuiteNodes->length === 0) { + $testSuiteNodes = $xpath->query('testsuite'); + + assert($testSuiteNodes instanceof DOMNodeList); + } + + if ($testSuiteNodes->length === 1) { + $element = $testSuiteNodes->item(0); + + assert($element instanceof DOMElement); + + $elements[] = $element; + } else { + foreach ($testSuiteNodes as $testSuiteNode) { + assert($testSuiteNode instanceof DOMElement); + + $elements[] = $testSuiteNode; + } + } + + return $elements; + } + + private function element(DOMXPath $xpath, string $element): ?DOMElement + { + $nodes = $xpath->query($element); + + assert($nodes instanceof DOMNodeList); + + if ($nodes->length === 1) { + $node = $nodes->item(0); + + assert($node instanceof DOMElement); + + return $node; + } + + return null; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/Junit.php b/src/TextUI/Configuration/Xml/Logging/Junit.php new file mode 100644 index 00000000000..cf9878dfd25 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/Junit.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Junit +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/Logging.php b/src/TextUI/Configuration/Xml/Logging/Logging.php new file mode 100644 index 00000000000..63f4d89fc9c --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/Logging.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\XmlConfiguration\Exception; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Html as TestDoxHtml; +use PHPUnit\TextUI\XmlConfiguration\Logging\TestDox\Text as TestDoxText; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Logging +{ + private ?Junit $junit; + private ?Otr $otr; + private ?TeamCity $teamCity; + private ?TestDoxHtml $testDoxHtml; + private ?TestDoxText $testDoxText; + + public function __construct(?Junit $junit, ?Otr $otr, ?TeamCity $teamCity, ?TestDoxHtml $testDoxHtml, ?TestDoxText $testDoxText) + { + $this->junit = $junit; + $this->otr = $otr; + $this->teamCity = $teamCity; + $this->testDoxHtml = $testDoxHtml; + $this->testDoxText = $testDoxText; + } + + public function hasJunit(): bool + { + return $this->junit !== null; + } + + /** + * @throws Exception + */ + public function junit(): Junit + { + if ($this->junit === null) { + throw new Exception('Logger "JUnit XML" is not configured'); + } + + return $this->junit; + } + + public function hasOtr(): bool + { + return $this->otr !== null; + } + + /** + * @throws Exception + */ + public function otr(): Otr + { + if ($this->otr === null) { + throw new Exception('Logger "Open Test Reporting XML" is not configured'); + } + + return $this->otr; + } + + public function hasTeamCity(): bool + { + return $this->teamCity !== null; + } + + /** + * @throws Exception + */ + public function teamCity(): TeamCity + { + if ($this->teamCity === null) { + throw new Exception('Logger "Team City" is not configured'); + } + + return $this->teamCity; + } + + public function hasTestDoxHtml(): bool + { + return $this->testDoxHtml !== null; + } + + /** + * @throws Exception + */ + public function testDoxHtml(): TestDoxHtml + { + if ($this->testDoxHtml === null) { + throw new Exception('Logger "TestDox HTML" is not configured'); + } + + return $this->testDoxHtml; + } + + public function hasTestDoxText(): bool + { + return $this->testDoxText !== null; + } + + /** + * @throws Exception + */ + public function testDoxText(): TestDoxText + { + if ($this->testDoxText === null) { + throw new Exception('Logger "TestDox Text" is not configured'); + } + + return $this->testDoxText; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/Otr.php b/src/TextUI/Configuration/Xml/Logging/Otr.php new file mode 100644 index 00000000000..25cfc989862 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/Otr.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Otr +{ + private File $target; + private bool $includeGitInformation; + + public function __construct(File $target, bool $includeGitInformation) + { + $this->target = $target; + $this->includeGitInformation = $includeGitInformation; + } + + public function target(): File + { + return $this->target; + } + + public function includeGitInformation(): bool + { + return $this->includeGitInformation; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/TeamCity.php b/src/TextUI/Configuration/Xml/Logging/TeamCity.php new file mode 100644 index 00000000000..daf1ceccfd7 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/TeamCity.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class TeamCity +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/TestDox/Html.php b/src/TextUI/Configuration/Xml/Logging/TestDox/Html.php new file mode 100644 index 00000000000..60e9d4da342 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/TestDox/Html.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging\TestDox; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Html +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/Logging/TestDox/Text.php b/src/TextUI/Configuration/Xml/Logging/TestDox/Text.php new file mode 100644 index 00000000000..ed436c0a84b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Logging/TestDox/Text.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration\Logging\TestDox; + +use PHPUnit\TextUI\Configuration\File; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class Text +{ + private File $target; + + public function __construct(File $target) + { + $this->target = $target; + } + + public function target(): File + { + return $this->target; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/MigrationBuilder.php b/src/TextUI/Configuration/Xml/Migration/MigrationBuilder.php new file mode 100644 index 00000000000..6235c55f3fe --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/MigrationBuilder.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function version_compare; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MigrationBuilder +{ + /** + * @var non-empty-array> + */ + private const array AVAILABLE_MIGRATIONS = [ + '8.5' => [ + RemoveLogTypes::class, + ], + + '9.2' => [ + RemoveCacheTokensAttribute::class, + IntroduceCoverageElement::class, + MoveAttributesFromRootToCoverage::class, + MoveAttributesFromFilterWhitelistToCoverage::class, + MoveWhitelistIncludesToCoverage::class, + MoveWhitelistExcludesToCoverage::class, + RemoveEmptyFilter::class, + CoverageCloverToReport::class, + CoverageCrap4jToReport::class, + CoverageHtmlToReport::class, + CoveragePhpToReport::class, + CoverageTextToReport::class, + CoverageXmlToReport::class, + ConvertLogTypes::class, + ], + + '9.5' => [ + RemoveListeners::class, + RemoveTestSuiteLoaderAttributes::class, + RemoveCacheResultFileAttribute::class, + RemoveCoverageElementCacheDirectoryAttribute::class, + RemoveCoverageElementProcessUncoveredFilesAttribute::class, + IntroduceCacheDirectoryAttribute::class, + RenameBackupStaticAttributesAttribute::class, + RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute::class, + RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class, + RemovePrinterAttributes::class, + RemoveVerboseAttribute::class, + RenameForceCoversAnnotationAttribute::class, + RenameBeStrictAboutCoversAnnotationAttribute::class, + RemoveConversionToExceptionsAttributes::class, + RemoveNoInteractionAttribute::class, + RemoveLoggingElements::class, + RemoveTestDoxGroupsElement::class, + ], + + '10.0' => [ + MoveCoverageDirectoriesToSource::class, + ], + + '10.4' => [ + RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class, + ], + + '10.5' => [ + RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute::class, + ], + + '11.0' => [ + ReplaceRestrictDeprecationsWithIgnoreDeprecations::class, + ], + + '11.1' => [ + RemoveCacheResultFileAttribute::class, + RemoveCoverageElementCacheDirectoryAttribute::class, + ], + + '11.2' => [ + RemoveBeStrictAboutTodoAnnotatedTestsAttribute::class, + ], + ]; + + /** + * @return non-empty-list + */ + public function build(string $fromVersion): array + { + $stack = [new UpdateSchemaLocation]; + + foreach (self::AVAILABLE_MIGRATIONS as $version => $migrations) { + if (version_compare($version, $fromVersion, '<')) { + continue; + } + + foreach ($migrations as $migration) { + $stack[] = new $migration; + } + } + + return $stack; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/MigrationException.php b/src/TextUI/Configuration/Xml/Migration/MigrationException.php new file mode 100644 index 00000000000..bb35aca6817 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/MigrationException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class MigrationException extends RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php b/src/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php new file mode 100644 index 00000000000..81a0e322abc --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/ConvertLogTypes.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ConvertLogTypes implements Migration +{ + public function migrate(DOMDocument $document): void + { + $logging = $document->getElementsByTagName('logging')->item(0); + + if (!$logging instanceof DOMElement) { + return; + } + $types = [ + 'junit' => 'junit', + 'teamcity' => 'teamcity', + 'testdox-html' => 'testdoxHtml', + 'testdox-text' => 'testdoxText', + 'testdox-xml' => 'testdoxXml', + 'plain' => 'text', + ]; + + $logNodes = []; + + foreach ($logging->getElementsByTagName('log') as $logNode) { + if (!isset($types[$logNode->getAttribute('type')])) { + continue; + } + + $logNodes[] = $logNode; + } + + foreach ($logNodes as $oldNode) { + $newLogNode = $document->createElement($types[$oldNode->getAttribute('type')]); + $newLogNode->setAttribute('outputFile', $oldNode->getAttribute('target')); + + $logging->replaceChild($newLogNode, $oldNode); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php new file mode 100644 index 00000000000..0dfee46fda2 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCloverToReport.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageCloverToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-clover'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $clover = $logNode->ownerDocument->createElement('clover'); + + $clover->setAttribute('outputFile', $logNode->getAttribute('target')); + + return $clover; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php new file mode 100644 index 00000000000..f0aac5c7c9b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageCrap4jToReport.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageCrap4jToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-crap4j'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $crap4j = $logNode->ownerDocument->createElement('crap4j'); + $crap4j->setAttribute('outputFile', $logNode->getAttribute('target')); + + $this->migrateAttributes($logNode, $crap4j, ['threshold']); + + return $crap4j; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php new file mode 100644 index 00000000000..f6b7982d98b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageHtmlToReport.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageHtmlToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-html'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $html = $logNode->ownerDocument->createElement('html'); + $html->setAttribute('outputDirectory', $logNode->getAttribute('target')); + + $this->migrateAttributes($logNode, $html, ['lowUpperBound', 'highLowerBound']); + + return $html; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php new file mode 100644 index 00000000000..7e362708b3e --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoveragePhpToReport.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoveragePhpToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-php'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $php = $logNode->ownerDocument->createElement('php'); + $php->setAttribute('outputFile', $logNode->getAttribute('target')); + + return $php; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php new file mode 100644 index 00000000000..d463cef8d45 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageTextToReport.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageTextToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-text'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $text = $logNode->ownerDocument->createElement('text'); + $text->setAttribute('outputFile', $logNode->getAttribute('target')); + + $this->migrateAttributes($logNode, $text, ['showUncoveredFiles', 'showOnlySummary']); + + return $text; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php new file mode 100644 index 00000000000..3db89974215 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/CoverageXmlToReport.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class CoverageXmlToReport extends LogToReportMigration +{ + protected function forType(): string + { + return 'coverage-xml'; + } + + protected function toReportFormat(DOMElement $logNode): DOMElement + { + $xml = $logNode->ownerDocument->createElement('xml'); + $xml->setAttribute('outputDirectory', $logNode->getAttribute('target')); + + return $xml; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php new file mode 100644 index 00000000000..87624cc6dec --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCacheDirectoryAttribute.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IntroduceCacheDirectoryAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('cacheDirectory')) { + return; + } + + $root->setAttribute('cacheDirectory', '.phpunit.cache'); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php b/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php new file mode 100644 index 00000000000..9334c1f43f4 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/IntroduceCoverageElement.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class IntroduceCoverageElement implements Migration +{ + public function migrate(DOMDocument $document): void + { + $coverage = $document->createElement('coverage'); + + $document->documentElement->insertBefore( + $coverage, + $document->documentElement->firstChild, + ); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php b/src/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php new file mode 100644 index 00000000000..08815cbcb31 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/LogToReportMigration.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function sprintf; +use DOMDocument; +use DOMElement; +use DOMXPath; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class LogToReportMigration implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if (!$coverage instanceof DOMElement) { + throw new MigrationException('Unexpected state - No coverage element'); + } + + $logNode = $this->findLogNode($document); + + if ($logNode === null) { + return; + } + + $reportChild = $this->toReportFormat($logNode); + + $report = $coverage->getElementsByTagName('report')->item(0); + + if ($report === null) { + $report = $coverage->appendChild($document->createElement('report')); + } + + $report->appendChild($reportChild); + $logNode->parentNode->removeChild($logNode); + } + + /** + * @param list $attributes + */ + protected function migrateAttributes(DOMElement $src, DOMElement $dest, array $attributes): void + { + foreach ($attributes as $attr) { + if (!$src->hasAttribute($attr)) { + continue; + } + + $dest->setAttribute($attr, $src->getAttribute($attr)); + $src->removeAttribute($attr); + } + } + + abstract protected function forType(): string; + + abstract protected function toReportFormat(DOMElement $logNode): DOMElement; + + private function findLogNode(DOMDocument $document): ?DOMElement + { + $xpath = new DOMXPath($document); + + $logNode = $xpath->query( + sprintf( + '//logging/log[@type="%s"]', + $this->forType(), + ), + ); + + assert($logNode !== false); + + $logNode = $logNode->item(0); + + if (!$logNode instanceof DOMElement) { + return null; + } + + return $logNode; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/Migration.php b/src/TextUI/Configuration/Xml/Migration/Migrations/Migration.php new file mode 100644 index 00000000000..05359a2d082 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/Migration.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Migration +{ + public function migrate(DOMDocument $document): void; +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php new file mode 100644 index 00000000000..685381698cb --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromFilterWhitelistToCoverage.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveAttributesFromFilterWhitelistToCoverage implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + + if ($whitelist === null) { + return; + } + + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if (!$coverage instanceof DOMElement) { + throw new MigrationException('Unexpected state - No coverage element'); + } + + $map = [ + 'addUncoveredFilesFromWhitelist' => 'includeUncoveredFiles', + 'processUncoveredFilesFromWhitelist' => 'processUncoveredFiles', + ]; + + foreach ($map as $old => $new) { + if (!$whitelist->hasAttribute($old)) { + continue; + } + + $coverage->setAttribute($new, $whitelist->getAttribute($old)); + $whitelist->removeAttribute($old); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php new file mode 100644 index 00000000000..f0e47b90fe4 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveAttributesFromRootToCoverage.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveAttributesFromRootToCoverage implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $map = [ + 'disableCodeCoverageIgnore' => 'disableCodeCoverageIgnore', + 'ignoreDeprecatedCodeUnitsFromCodeCoverage' => 'ignoreDeprecatedCodeUnits', + ]; + + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if (!$coverage instanceof DOMElement) { + throw new MigrationException('Unexpected state - No coverage element'); + } + + foreach ($map as $old => $new) { + if (!$root->hasAttribute($old)) { + continue; + } + + $coverage->setAttribute($new, $root->getAttribute($old)); + $root->removeAttribute($old); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php new file mode 100644 index 00000000000..4dd37ea5158 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveCoverageDirectoriesToSource.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +use DOMXPath; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveCoverageDirectoriesToSource implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $source = $document->getElementsByTagName('source')->item(0); + + if ($source !== null) { + return; + } + + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if ($coverage === null) { + return; + } + + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + $source = $document->createElement('source'); + $root->appendChild($source); + + $xpath = new DOMXPath($document); + + foreach (['include', 'exclude'] as $element) { + $nodes = $xpath->query('//coverage/' . $element); + + assert($nodes !== false); + + foreach (SnapshotNodeList::fromNodeList($nodes) as $node) { + $source->appendChild($node); + } + } + + if ($coverage->childElementCount !== 0) { + return; + } + + assert($coverage->parentNode !== null); + + $coverage->parentNode->removeChild($coverage); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php new file mode 100644 index 00000000000..09641bb13b7 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistExcludesToCoverage.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function in_array; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveWhitelistExcludesToCoverage implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + + if ($whitelist === null) { + return; + } + + $excludeNodes = SnapshotNodeList::fromNodeList($whitelist->getElementsByTagName('exclude')); + + if ($excludeNodes->count() === 0) { + return; + } + + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if (!$coverage instanceof DOMElement) { + throw new MigrationException('Unexpected state - No coverage element'); + } + + $targetExclude = $coverage->getElementsByTagName('exclude')->item(0); + + if ($targetExclude === null) { + $targetExclude = $coverage->appendChild( + $document->createElement('exclude'), + ); + } + + foreach ($excludeNodes as $excludeNode) { + assert($excludeNode instanceof DOMElement); + + foreach (SnapshotNodeList::fromNodeList($excludeNode->childNodes) as $child) { + if (!$child instanceof DOMElement || !in_array($child->nodeName, ['directory', 'file'], true)) { + continue; + } + + $targetExclude->appendChild($child); + } + + if ($excludeNode->getElementsByTagName('*')->count() !== 0) { + throw new MigrationException('Dangling child elements in exclude found.'); + } + + $whitelist->removeChild($excludeNode); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php new file mode 100644 index 00000000000..9990124963d --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/MoveWhitelistIncludesToCoverage.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class MoveWhitelistIncludesToCoverage implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + + if ($whitelist === null) { + return; + } + + $coverage = $document->getElementsByTagName('coverage')->item(0); + + if (!$coverage instanceof DOMElement) { + throw new MigrationException('Unexpected state - No coverage element'); + } + + $include = $document->createElement('include'); + $coverage->appendChild($include); + + foreach (SnapshotNodeList::fromNodeList($whitelist->childNodes) as $child) { + if (!$child instanceof DOMElement) { + continue; + } + + if (!($child->nodeName === 'directory' || $child->nodeName === 'file')) { + continue; + } + + $include->appendChild($child); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php new file mode 100644 index 00000000000..cdb90775cd9 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveBeStrictAboutResourceUsageDuringSmallTestsAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('beStrictAboutResourceUsageDuringSmallTests')) { + $root->removeAttribute('beStrictAboutResourceUsageDuringSmallTests'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php new file mode 100644 index 00000000000..1858e67f42b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveBeStrictAboutTodoAnnotatedTestsAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveBeStrictAboutTodoAnnotatedTestsAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('beStrictAboutTodoAnnotatedTests')) { + $root->removeAttribute('beStrictAboutTodoAnnotatedTests'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php new file mode 100644 index 00000000000..a5c51c4ebc3 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheResultFileAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCacheResultFileAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('cacheResultFile')) { + $root->removeAttribute('cacheResultFile'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php new file mode 100644 index 00000000000..69bf38a21f3 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCacheTokensAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCacheTokensAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('cacheTokens')) { + $root->removeAttribute('cacheTokens'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php new file mode 100644 index 00000000000..a908aee381f --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveConversionToExceptionsAttributes.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveConversionToExceptionsAttributes implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('convertDeprecationsToExceptions')) { + $root->removeAttribute('convertDeprecationsToExceptions'); + } + + if ($root->hasAttribute('convertErrorsToExceptions')) { + $root->removeAttribute('convertErrorsToExceptions'); + } + + if ($root->hasAttribute('convertNoticesToExceptions')) { + $root->removeAttribute('convertNoticesToExceptions'); + } + + if ($root->hasAttribute('convertWarningsToExceptions')) { + $root->removeAttribute('convertWarningsToExceptions'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php new file mode 100644 index 00000000000..c26d2071c72 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementCacheDirectoryAttribute.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCoverageElementCacheDirectoryAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('coverage')->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + if ($node->hasAttribute('cacheDirectory')) { + $node->removeAttribute('cacheDirectory'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php new file mode 100644 index 00000000000..34768625101 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveCoverageElementProcessUncoveredFilesAttribute.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveCoverageElementProcessUncoveredFilesAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('coverage')->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + if ($node->hasAttribute('processUncoveredFiles')) { + $node->removeAttribute('processUncoveredFiles'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php new file mode 100644 index 00000000000..a831e205109 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveEmptyFilter.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function sprintf; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveEmptyFilter implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $whitelist = $document->getElementsByTagName('whitelist')->item(0); + + if ($whitelist instanceof DOMElement) { + $this->ensureEmpty($whitelist); + $whitelist->parentNode->removeChild($whitelist); + } + + $filter = $document->getElementsByTagName('filter')->item(0); + + if ($filter instanceof DOMElement) { + $this->ensureEmpty($filter); + $filter->parentNode->removeChild($filter); + } + } + + /** + * @throws MigrationException + */ + private function ensureEmpty(DOMElement $element): void + { + if ($element->attributes->length > 0) { + throw new MigrationException(sprintf('%s element has unexpected attributes', $element->nodeName)); + } + + if ($element->getElementsByTagName('*')->length > 0) { + throw new MigrationException(sprintf('%s element has unexpected children', $element->nodeName)); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php new file mode 100644 index 00000000000..bf2889965de --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveListeners.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveListeners implements Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('listeners')->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + $node->parentNode->removeChild($node); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.php new file mode 100644 index 00000000000..46ee55e925b --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLogTypes.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveLogTypes implements Migration +{ + public function migrate(DOMDocument $document): void + { + $logging = $document->getElementsByTagName('logging')->item(0); + + if (!$logging instanceof DOMElement) { + return; + } + + foreach (SnapshotNodeList::fromNodeList($logging->getElementsByTagName('log')) as $logNode) { + assert($logNode instanceof DOMElement); + + switch ($logNode->getAttribute('type')) { + case 'json': + case 'tap': + $logging->removeChild($logNode); + } + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php new file mode 100644 index 00000000000..d40ab029cd1 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveLoggingElements.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; +use DOMXPath; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveLoggingElements implements Migration +{ + public function migrate(DOMDocument $document): void + { + $this->removeTestDoxElement($document); + $this->removeTextElement($document); + } + + private function removeTestDoxElement(DOMDocument $document): void + { + $nodes = new DOMXPath($document)->query('logging/testdoxXml'); + + assert($nodes !== false); + + $node = $nodes->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + $node->parentNode->removeChild($node); + } + + private function removeTextElement(DOMDocument $document): void + { + $nodes = new DOMXPath($document)->query('logging/text'); + + assert($nodes !== false); + + $node = $nodes->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + $node->parentNode->removeChild($node); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php new file mode 100644 index 00000000000..897cccd81bd --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveNoInteractionAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveNoInteractionAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('noInteraction')) { + $root->removeAttribute('noInteraction'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php new file mode 100644 index 00000000000..84f4bcf1add --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemovePrinterAttributes.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemovePrinterAttributes implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('printerClass')) { + $root->removeAttribute('printerClass'); + } + + if ($root->hasAttribute('printerFile')) { + $root->removeAttribute('printerFile'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php new file mode 100644 index 00000000000..e2ff30514f9 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveRegisterMockObjectsFromTestArgumentsRecursivelyAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('registerMockObjectsFromTestArgumentsRecursively')) { + $root->removeAttribute('registerMockObjectsFromTestArgumentsRecursively'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php new file mode 100644 index 00000000000..ea5a69217be --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestDoxGroupsElement.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveTestDoxGroupsElement implements Migration +{ + public function migrate(DOMDocument $document): void + { + $node = $document->getElementsByTagName('testdoxGroups')->item(0); + + if (!$node instanceof DOMElement || $node->parentNode === null) { + return; + } + + $node->parentNode->removeChild($node); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php new file mode 100644 index 00000000000..284dda2ef88 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveTestSuiteLoaderAttributes.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveTestSuiteLoaderAttributes implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('testSuiteLoaderClass')) { + $root->removeAttribute('testSuiteLoaderClass'); + } + + if ($root->hasAttribute('testSuiteLoaderFile')) { + $root->removeAttribute('testSuiteLoaderFile'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php new file mode 100644 index 00000000000..d4aa66087bb --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RemoveVerboseAttribute.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RemoveVerboseAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('verbose')) { + $root->removeAttribute('verbose'); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php new file mode 100644 index 00000000000..c2de95ce38c --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBackupStaticAttributesAttribute.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameBackupStaticAttributesAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('backupStaticProperties')) { + return; + } + + if (!$root->hasAttribute('backupStaticAttributes')) { + return; + } + + $root->setAttribute('backupStaticProperties', $root->getAttribute('backupStaticAttributes')); + $root->removeAttribute('backupStaticAttributes'); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php new file mode 100644 index 00000000000..dda890b66cb --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameBeStrictAboutCoversAnnotationAttribute.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameBeStrictAboutCoversAnnotationAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('beStrictAboutCoverageMetadata')) { + return; + } + + if (!$root->hasAttribute('beStrictAboutCoversAnnotation')) { + return; + } + + $root->setAttribute('beStrictAboutCoverageMetadata', $root->getAttribute('beStrictAboutCoversAnnotation')); + $root->removeAttribute('beStrictAboutCoversAnnotation'); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php new file mode 100644 index 00000000000..707aff8a368 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/RenameForceCoversAnnotationAttribute.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class RenameForceCoversAnnotationAttribute implements Migration +{ + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + if ($root->hasAttribute('requireCoverageMetadata')) { + return; + } + + if (!$root->hasAttribute('forceCoversAnnotation')) { + return; + } + + $root->setAttribute('requireCoverageMetadata', $root->getAttribute('forceCoversAnnotation')); + $root->removeAttribute('forceCoversAnnotation'); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php b/src/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php new file mode 100644 index 00000000000..12cb1e7f087 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/ReplaceRestrictDeprecationsWithIgnoreDeprecations.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use DOMDocument; +use DOMElement; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ReplaceRestrictDeprecationsWithIgnoreDeprecations implements Migration +{ + /** + * @throws MigrationException + */ + public function migrate(DOMDocument $document): void + { + $source = $document->getElementsByTagName('source')->item(0); + + if ($source === null) { + return; + } + + assert($source instanceof DOMElement); + + if (!$source->hasAttribute('restrictDeprecations')) { + return; + } + + $restrictDeprecations = $source->getAttribute('restrictDeprecations') === 'true'; + + $source->removeAttribute('restrictDeprecations'); + + if (!$restrictDeprecations || + $source->hasAttribute('ignoreIndirectDeprecations')) { + return; + } + + $source->setAttribute('ignoreIndirectDeprecations', 'true'); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php b/src/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php new file mode 100644 index 00000000000..85b0b568e63 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrations/UpdateSchemaLocation.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function str_contains; +use DOMDocument; +use DOMElement; +use PHPUnit\Runner\Version; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UpdateSchemaLocation implements Migration +{ + private const string NAMESPACE_URI = 'http://www.w3.org/2001/XMLSchema-instance'; + private const string LOCAL_NAME_SCHEMA_LOCATION = 'noNamespaceSchemaLocation'; + + public function migrate(DOMDocument $document): void + { + $root = $document->documentElement; + + assert($root instanceof DOMElement); + + $existingSchemaLocation = $root->getAttributeNS(self::NAMESPACE_URI, self::LOCAL_NAME_SCHEMA_LOCATION); + + if (str_contains($existingSchemaLocation, '://') === false) { // If the current schema location is a relative path, don't update it + return; + } + + $root->setAttributeNS( + self::NAMESPACE_URI, + 'xsi:' . self::LOCAL_NAME_SCHEMA_LOCATION, + 'https://schema.phpunit.de/' . Version::series() . '/phpunit.xsd', + ); + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/Migrator.php b/src/TextUI/Configuration/Xml/Migration/Migrator.php new file mode 100644 index 00000000000..4649dec28e4 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/Migrator.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use PHPUnit\Runner\Version; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use PHPUnit\Util\Xml\XmlException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Migrator +{ + /** + * @throws Exception + * @throws MigrationException + * @throws XmlException + */ + public function migrate(string $filename): string + { + $origin = (new SchemaDetector)->detect($filename); + + if (!$origin->detected()) { + throw new Exception('The file does not validate against any known schema'); + } + + if ($origin->version() === Version::series()) { + throw new Exception('The file does not need to be migrated'); + } + + $configurationDocument = (new XmlLoader)->loadFile($filename); + + foreach ((new MigrationBuilder)->build($origin->version()) as $migration) { + $migration->migrate($configurationDocument); + } + + $configurationDocument->formatOutput = true; + $configurationDocument->preserveWhiteSpace = false; + + $xml = $configurationDocument->saveXML(); + + assert($xml !== false); + + return $xml; + } +} diff --git a/src/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php b/src/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php new file mode 100644 index 00000000000..491c24edace --- /dev/null +++ b/src/TextUI/Configuration/Xml/Migration/SnapshotNodeList.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function count; +use ArrayIterator; +use Countable; +use DOMNode; +use DOMNodeList; +use IteratorAggregate; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @template-implements IteratorAggregate + */ +final class SnapshotNodeList implements Countable, IteratorAggregate +{ + /** + * @var list + */ + private array $nodes = []; + + /** + * @param DOMNodeList $list + */ + public static function fromNodeList(DOMNodeList $list): self + { + $snapshot = new self; + + foreach ($list as $node) { + $snapshot->nodes[] = $node; + } + + return $snapshot; + } + + public function count(): int + { + return count($this->nodes); + } + + /** + * @return ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->nodes); + } +} diff --git a/src/TextUI/Configuration/Xml/PHPUnit.php b/src/TextUI/Configuration/Xml/PHPUnit.php new file mode 100644 index 00000000000..0b384e7399e --- /dev/null +++ b/src/TextUI/Configuration/Xml/PHPUnit.php @@ -0,0 +1,530 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class PHPUnit +{ + private ?string $cacheDirectory; + private bool $cacheResult; + private int|string $columns; + private string $colors; + private bool $stderr; + private bool $displayDetailsOnAllIssues; + private bool $displayDetailsOnIncompleteTests; + private bool $displayDetailsOnSkippedTests; + private bool $displayDetailsOnTestsThatTriggerDeprecations; + private bool $displayDetailsOnPhpunitDeprecations; + private bool $displayDetailsOnPhpunitNotices; + private bool $displayDetailsOnTestsThatTriggerErrors; + private bool $displayDetailsOnTestsThatTriggerNotices; + private bool $displayDetailsOnTestsThatTriggerWarnings; + private bool $reverseDefectList; + private bool $requireCoverageMetadata; + private ?string $bootstrap; + + /** + * @var array + */ + private array $bootstrapForTestSuite; + private bool $processIsolation; + private bool $failOnAllIssues; + private bool $failOnDeprecation; + private bool $failOnPhpunitDeprecation; + private bool $failOnPhpunitNotice; + private bool $failOnPhpunitWarning; + private bool $failOnEmptyTestSuite; + private bool $failOnIncomplete; + private bool $failOnNotice; + private bool $failOnRisky; + private bool $failOnSkipped; + private bool $failOnWarning; + private bool $stopOnDefect; + private bool $stopOnDeprecation; + private bool $stopOnError; + private bool $stopOnFailure; + private bool $stopOnIncomplete; + private bool $stopOnNotice; + private bool $stopOnRisky; + private bool $stopOnSkipped; + private bool $stopOnWarning; + + /** + * @var ?non-empty-string + */ + private ?string $extensionsDirectory; + private bool $beStrictAboutChangesToGlobalState; + private bool $beStrictAboutOutputDuringTests; + private bool $beStrictAboutTestsThatDoNotTestAnything; + private bool $beStrictAboutCoverageMetadata; + private bool $enforceTimeLimit; + private int $defaultTimeLimit; + private int $timeoutForSmallTests; + private int $timeoutForMediumTests; + private int $timeoutForLargeTests; + private ?string $defaultTestSuite; + private int $executionOrder; + private bool $resolveDependencies; + private bool $defectsFirst; + private bool $backupGlobals; + private bool $backupStaticProperties; + private bool $testdoxPrinter; + private bool $testdoxPrinterSummary; + private bool $controlGarbageCollector; + private int $numberOfTestsBeforeGarbageCollection; + + /** + * @var non-negative-int + */ + private int $shortenArraysForExportThreshold; + + /** + * @param array $bootstrapForTestSuite + * @param ?non-empty-string $extensionsDirectory + * @param non-negative-int $shortenArraysForExportThreshold + */ + public function __construct(?string $cacheDirectory, bool $cacheResult, int|string $columns, string $colors, bool $stderr, bool $displayDetailsOnAllIssues, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnPhpunitDeprecations, bool $displayDetailsOnPhpunitNotices, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $reverseDefectList, bool $requireCoverageMetadata, ?string $bootstrap, array $bootstrapForTestSuite, bool $processIsolation, bool $failOnAllIssues, bool $failOnDeprecation, bool $failOnPhpunitDeprecation, bool $failOnPhpunitNotice, bool $failOnPhpunitWarning, bool $failOnEmptyTestSuite, bool $failOnIncomplete, bool $failOnNotice, bool $failOnRisky, bool $failOnSkipped, bool $failOnWarning, bool $stopOnDefect, bool $stopOnDeprecation, bool $stopOnError, bool $stopOnFailure, bool $stopOnIncomplete, bool $stopOnNotice, bool $stopOnRisky, bool $stopOnSkipped, bool $stopOnWarning, ?string $extensionsDirectory, bool $beStrictAboutChangesToGlobalState, bool $beStrictAboutOutputDuringTests, bool $beStrictAboutTestsThatDoNotTestAnything, bool $beStrictAboutCoverageMetadata, bool $enforceTimeLimit, int $defaultTimeLimit, int $timeoutForSmallTests, int $timeoutForMediumTests, int $timeoutForLargeTests, ?string $defaultTestSuite, int $executionOrder, bool $resolveDependencies, bool $defectsFirst, bool $backupGlobals, bool $backupStaticProperties, bool $testdoxPrinter, bool $testdoxPrinterSummary, bool $controlGarbageCollector, int $numberOfTestsBeforeGarbageCollection, int $shortenArraysForExportThreshold) + { + $this->cacheDirectory = $cacheDirectory; + $this->cacheResult = $cacheResult; + $this->columns = $columns; + $this->colors = $colors; + $this->stderr = $stderr; + $this->displayDetailsOnAllIssues = $displayDetailsOnAllIssues; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnPhpunitDeprecations = $displayDetailsOnPhpunitDeprecations; + $this->displayDetailsOnPhpunitNotices = $displayDetailsOnPhpunitNotices; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->reverseDefectList = $reverseDefectList; + $this->requireCoverageMetadata = $requireCoverageMetadata; + $this->bootstrap = $bootstrap; + $this->bootstrapForTestSuite = $bootstrapForTestSuite; + $this->processIsolation = $processIsolation; + $this->failOnAllIssues = $failOnAllIssues; + $this->failOnDeprecation = $failOnDeprecation; + $this->failOnPhpunitDeprecation = $failOnPhpunitDeprecation; + $this->failOnPhpunitNotice = $failOnPhpunitNotice; + $this->failOnPhpunitWarning = $failOnPhpunitWarning; + $this->failOnEmptyTestSuite = $failOnEmptyTestSuite; + $this->failOnIncomplete = $failOnIncomplete; + $this->failOnNotice = $failOnNotice; + $this->failOnRisky = $failOnRisky; + $this->failOnSkipped = $failOnSkipped; + $this->failOnWarning = $failOnWarning; + $this->stopOnDefect = $stopOnDefect; + $this->stopOnDeprecation = $stopOnDeprecation; + $this->stopOnError = $stopOnError; + $this->stopOnFailure = $stopOnFailure; + $this->stopOnIncomplete = $stopOnIncomplete; + $this->stopOnNotice = $stopOnNotice; + $this->stopOnRisky = $stopOnRisky; + $this->stopOnSkipped = $stopOnSkipped; + $this->stopOnWarning = $stopOnWarning; + $this->extensionsDirectory = $extensionsDirectory; + $this->beStrictAboutChangesToGlobalState = $beStrictAboutChangesToGlobalState; + $this->beStrictAboutOutputDuringTests = $beStrictAboutOutputDuringTests; + $this->beStrictAboutTestsThatDoNotTestAnything = $beStrictAboutTestsThatDoNotTestAnything; + $this->beStrictAboutCoverageMetadata = $beStrictAboutCoverageMetadata; + $this->enforceTimeLimit = $enforceTimeLimit; + $this->defaultTimeLimit = $defaultTimeLimit; + $this->timeoutForSmallTests = $timeoutForSmallTests; + $this->timeoutForMediumTests = $timeoutForMediumTests; + $this->timeoutForLargeTests = $timeoutForLargeTests; + $this->defaultTestSuite = $defaultTestSuite; + $this->executionOrder = $executionOrder; + $this->resolveDependencies = $resolveDependencies; + $this->defectsFirst = $defectsFirst; + $this->backupGlobals = $backupGlobals; + $this->backupStaticProperties = $backupStaticProperties; + $this->testdoxPrinter = $testdoxPrinter; + $this->testdoxPrinterSummary = $testdoxPrinterSummary; + $this->controlGarbageCollector = $controlGarbageCollector; + $this->numberOfTestsBeforeGarbageCollection = $numberOfTestsBeforeGarbageCollection; + $this->shortenArraysForExportThreshold = $shortenArraysForExportThreshold; + } + + /** + * @phpstan-assert-if-true !null $this->cacheDirectory + */ + public function hasCacheDirectory(): bool + { + return $this->cacheDirectory !== null; + } + + /** + * @throws Exception + */ + public function cacheDirectory(): string + { + if (!$this->hasCacheDirectory()) { + throw new Exception('Cache directory is not configured'); + } + + return $this->cacheDirectory; + } + + public function cacheResult(): bool + { + return $this->cacheResult; + } + + public function columns(): int|string + { + return $this->columns; + } + + public function colors(): string + { + return $this->colors; + } + + public function stderr(): bool + { + return $this->stderr; + } + + public function displayDetailsOnAllIssues(): bool + { + return $this->displayDetailsOnAllIssues; + } + + public function displayDetailsOnIncompleteTests(): bool + { + return $this->displayDetailsOnIncompleteTests; + } + + public function displayDetailsOnSkippedTests(): bool + { + return $this->displayDetailsOnSkippedTests; + } + + public function displayDetailsOnTestsThatTriggerDeprecations(): bool + { + return $this->displayDetailsOnTestsThatTriggerDeprecations; + } + + public function displayDetailsOnPhpunitDeprecations(): bool + { + return $this->displayDetailsOnPhpunitDeprecations; + } + + public function displayDetailsOnPhpunitNotices(): bool + { + return $this->displayDetailsOnPhpunitNotices; + } + + public function displayDetailsOnTestsThatTriggerErrors(): bool + { + return $this->displayDetailsOnTestsThatTriggerErrors; + } + + public function displayDetailsOnTestsThatTriggerNotices(): bool + { + return $this->displayDetailsOnTestsThatTriggerNotices; + } + + public function displayDetailsOnTestsThatTriggerWarnings(): bool + { + return $this->displayDetailsOnTestsThatTriggerWarnings; + } + + public function reverseDefectList(): bool + { + return $this->reverseDefectList; + } + + public function requireCoverageMetadata(): bool + { + return $this->requireCoverageMetadata; + } + + /** + * @phpstan-assert-if-true !null $this->bootstrap + */ + public function hasBootstrap(): bool + { + return $this->bootstrap !== null; + } + + /** + * @throws Exception + */ + public function bootstrap(): string + { + if (!$this->hasBootstrap()) { + throw new Exception('Bootstrap script is not configured'); + } + + return $this->bootstrap; + } + + /** + * @return array + */ + public function bootstrapForTestSuite(): array + { + return $this->bootstrapForTestSuite; + } + + public function processIsolation(): bool + { + return $this->processIsolation; + } + + public function failOnAllIssues(): bool + { + return $this->failOnAllIssues; + } + + public function failOnDeprecation(): bool + { + return $this->failOnDeprecation; + } + + public function failOnPhpunitDeprecation(): bool + { + return $this->failOnPhpunitDeprecation; + } + + public function failOnPhpunitNotice(): bool + { + return $this->failOnPhpunitNotice; + } + + public function failOnPhpunitWarning(): bool + { + return $this->failOnPhpunitWarning; + } + + public function failOnEmptyTestSuite(): bool + { + return $this->failOnEmptyTestSuite; + } + + public function failOnIncomplete(): bool + { + return $this->failOnIncomplete; + } + + public function failOnNotice(): bool + { + return $this->failOnNotice; + } + + public function failOnRisky(): bool + { + return $this->failOnRisky; + } + + public function failOnSkipped(): bool + { + return $this->failOnSkipped; + } + + public function failOnWarning(): bool + { + return $this->failOnWarning; + } + + public function stopOnDefect(): bool + { + return $this->stopOnDefect; + } + + public function stopOnDeprecation(): bool + { + return $this->stopOnDeprecation; + } + + public function stopOnError(): bool + { + return $this->stopOnError; + } + + public function stopOnFailure(): bool + { + return $this->stopOnFailure; + } + + public function stopOnIncomplete(): bool + { + return $this->stopOnIncomplete; + } + + public function stopOnNotice(): bool + { + return $this->stopOnNotice; + } + + public function stopOnRisky(): bool + { + return $this->stopOnRisky; + } + + public function stopOnSkipped(): bool + { + return $this->stopOnSkipped; + } + + public function stopOnWarning(): bool + { + return $this->stopOnWarning; + } + + /** + * @phpstan-assert-if-true !null $this->extensionsDirectory + */ + public function hasExtensionsDirectory(): bool + { + return $this->extensionsDirectory !== null; + } + + /** + * @throws Exception + * + * @return non-empty-string + */ + public function extensionsDirectory(): string + { + if (!$this->hasExtensionsDirectory()) { + throw new Exception('Extensions directory is not configured'); + } + + return $this->extensionsDirectory; + } + + public function beStrictAboutChangesToGlobalState(): bool + { + return $this->beStrictAboutChangesToGlobalState; + } + + public function beStrictAboutOutputDuringTests(): bool + { + return $this->beStrictAboutOutputDuringTests; + } + + public function beStrictAboutTestsThatDoNotTestAnything(): bool + { + return $this->beStrictAboutTestsThatDoNotTestAnything; + } + + public function beStrictAboutCoverageMetadata(): bool + { + return $this->beStrictAboutCoverageMetadata; + } + + public function enforceTimeLimit(): bool + { + return $this->enforceTimeLimit; + } + + public function defaultTimeLimit(): int + { + return $this->defaultTimeLimit; + } + + public function timeoutForSmallTests(): int + { + return $this->timeoutForSmallTests; + } + + public function timeoutForMediumTests(): int + { + return $this->timeoutForMediumTests; + } + + public function timeoutForLargeTests(): int + { + return $this->timeoutForLargeTests; + } + + /** + * @phpstan-assert-if-true !null $this->defaultTestSuite + */ + public function hasDefaultTestSuite(): bool + { + return $this->defaultTestSuite !== null; + } + + /** + * @throws Exception + */ + public function defaultTestSuite(): string + { + if (!$this->hasDefaultTestSuite()) { + throw new Exception('Default test suite is not configured'); + } + + return $this->defaultTestSuite; + } + + public function executionOrder(): int + { + return $this->executionOrder; + } + + public function resolveDependencies(): bool + { + return $this->resolveDependencies; + } + + public function defectsFirst(): bool + { + return $this->defectsFirst; + } + + public function backupGlobals(): bool + { + return $this->backupGlobals; + } + + public function backupStaticProperties(): bool + { + return $this->backupStaticProperties; + } + + public function testdoxPrinter(): bool + { + return $this->testdoxPrinter; + } + + public function testdoxPrinterSummary(): bool + { + return $this->testdoxPrinterSummary; + } + + public function controlGarbageCollector(): bool + { + return $this->controlGarbageCollector; + } + + public function numberOfTestsBeforeGarbageCollection(): int + { + return $this->numberOfTestsBeforeGarbageCollection; + } + + /** + * @return non-negative-int + */ + public function shortenArraysForExportThreshold(): int + { + return $this->shortenArraysForExportThreshold; + } +} diff --git a/src/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php b/src/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php new file mode 100644 index 00000000000..5bd282c8c3b --- /dev/null +++ b/src/TextUI/Configuration/Xml/SchemaDetector/FailedSchemaDetectionResult.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class FailedSchemaDetectionResult extends SchemaDetectionResult +{ +} diff --git a/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php b/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php new file mode 100644 index 00000000000..aa855b0cb06 --- /dev/null +++ b/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetectionResult.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Util\Xml\XmlException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +abstract readonly class SchemaDetectionResult +{ + /** + * @phpstan-assert-if-true SuccessfulSchemaDetectionResult $this + */ + public function detected(): bool + { + return false; + } + + /** + * @throws XmlException + */ + public function version(): string + { + throw new XmlException('No supported schema was detected'); + } +} diff --git a/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.php b/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.php new file mode 100644 index 00000000000..5f55f5f2016 --- /dev/null +++ b/src/TextUI/Configuration/Xml/SchemaDetector/SchemaDetector.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Util\Xml\Loader; +use PHPUnit\Util\Xml\XmlException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SchemaDetector +{ + /** + * @throws XmlException + */ + public function detect(string $filename): SchemaDetectionResult + { + $document = (new Loader)->loadFile($filename); + + $schemaFinder = new SchemaFinder; + + foreach ($schemaFinder->available() as $candidate) { + $schema = (new SchemaFinder)->find($candidate); + + if (!(new Validator)->validate($document, $schema)->hasValidationErrors()) { + return new SuccessfulSchemaDetectionResult($candidate); + } + } + + return new FailedSchemaDetectionResult; + } +} diff --git a/src/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php b/src/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php new file mode 100644 index 00000000000..72a64c193f4 --- /dev/null +++ b/src/TextUI/Configuration/Xml/SchemaDetector/SuccessfulSchemaDetectionResult.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class SuccessfulSchemaDetectionResult extends SchemaDetectionResult +{ + /** + * @var non-empty-string + */ + private string $version; + + /** + * @param non-empty-string $version + */ + public function __construct(string $version) + { + $this->version = $version; + } + + public function detected(): bool + { + return true; + } + + /** + * @throws void + * + * @return non-empty-string + */ + public function version(): string + { + return $this->version; + } +} diff --git a/src/TextUI/Configuration/Xml/SchemaFinder.php b/src/TextUI/Configuration/Xml/SchemaFinder.php new file mode 100644 index 00000000000..39d25cfadf5 --- /dev/null +++ b/src/TextUI/Configuration/Xml/SchemaFinder.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function defined; +use function is_file; +use function rsort; +use function sprintf; +use DirectoryIterator; +use PHPUnit\Runner\Version; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class SchemaFinder +{ + /** + * @return non-empty-list + */ + public function available(): array + { + $result = [Version::series()]; + + foreach ((new DirectoryIterator($this->path() . 'schema')) as $file) { + if ($file->isDot()) { + continue; + } + + $version = $file->getBasename('.xsd'); + + assert($version !== ''); + + $result[] = $version; + } + + rsort($result); + + return $result; + } + + /** + * @throws CannotFindSchemaException + */ + public function find(string $version): string + { + if ($version === Version::series()) { + $filename = $this->path() . 'phpunit.xsd'; + } else { + $filename = $this->path() . 'schema/' . $version . '.xsd'; + } + + if (!is_file($filename)) { + throw new CannotFindSchemaException( + sprintf( + 'Schema for PHPUnit %s is not available', + $version, + ), + ); + } + + return $filename; + } + + private function path(): string + { + if (defined('__PHPUNIT_PHAR_ROOT__')) { + return __PHPUNIT_PHAR_ROOT__ . '/'; + } + + return __DIR__ . '/../../../../'; + } +} diff --git a/src/TextUI/Configuration/Xml/TestSuiteMapper.php b/src/TextUI/Configuration/Xml/TestSuiteMapper.php new file mode 100644 index 00000000000..66bd611c1c6 --- /dev/null +++ b/src/TextUI/Configuration/Xml/TestSuiteMapper.php @@ -0,0 +1,150 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const PHP_VERSION; +use function in_array; +use function is_dir; +use function is_file; +use function sprintf; +use function str_contains; +use function version_compare; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Exception as FrameworkException; +use PHPUnit\Framework\TestSuite as TestSuiteObject; +use PHPUnit\TextUI\Configuration\TestSuiteCollection; +use PHPUnit\TextUI\RuntimeException; +use PHPUnit\TextUI\TestDirectoryNotFoundException; +use PHPUnit\TextUI\TestFileNotFoundException; +use SebastianBergmann\FileIterator\Facade; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteMapper +{ + /** + * @param non-empty-string $xmlConfigurationFile + * @param list $includeTestSuites + * @param list $excludeTestSuites + * + * @throws RuntimeException + * @throws TestDirectoryNotFoundException + * @throws TestFileNotFoundException + */ + public function map(string $xmlConfigurationFile, TestSuiteCollection $configuredTestSuites, array $includeTestSuites, array $excludeTestSuites): TestSuiteObject + { + try { + $result = TestSuiteObject::empty($xmlConfigurationFile); + $processed = []; + + foreach ($configuredTestSuites as $configuredTestSuite) { + if ($includeTestSuites !== [] && !in_array($configuredTestSuite->name(), $includeTestSuites, true)) { + continue; + } + + if ($excludeTestSuites !== [] && in_array($configuredTestSuite->name(), $excludeTestSuites, true)) { + continue; + } + + $testSuiteName = $configuredTestSuite->name(); + $exclude = []; + + foreach ($configuredTestSuite->exclude()->asArray() as $file) { + $exclude[] = $file->path(); + } + + $testSuite = TestSuiteObject::empty($configuredTestSuite->name()); + $empty = true; + + foreach ($configuredTestSuite->directories() as $directory) { + if (!str_contains($directory->path(), '*') && !is_dir($directory->path())) { + throw new TestDirectoryNotFoundException($directory->path()); + } + + if (!version_compare(PHP_VERSION, $directory->phpVersion(), $directory->phpVersionOperator()->asString())) { + continue; + } + + $files = (new Facade)->getFilesAsArray( + $directory->path(), + $directory->suffix(), + $directory->prefix(), + $exclude, + ); + + $groups = $directory->groups(); + + foreach ($files as $file) { + if (isset($processed[$file])) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot add file %s to test suite "%s" as it was already added to test suite "%s"', + $file, + $testSuiteName, + $processed[$file], + ), + ); + + continue; + } + + $processed[$file] = $testSuiteName; + $empty = false; + + $testSuite->addTestFile($file, $groups); + } + } + + foreach ($configuredTestSuite->files() as $file) { + if (!is_file($file->path())) { + throw new TestFileNotFoundException($file->path()); + } + + if (!version_compare(PHP_VERSION, $file->phpVersion(), $file->phpVersionOperator()->asString())) { + continue; + } + + if (isset($processed[$file->path()])) { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning( + sprintf( + 'Cannot add file %s to test suite "%s" as it was already added to test suite "%s"', + $file->path(), + $testSuiteName, + $processed[$file->path()], + ), + ); + + continue; + } + + $processed[$file->path()] = $testSuiteName; + $empty = false; + + $testSuite->addTestFile($file->path(), $file->groups()); + } + + if (!$empty) { + $result->addTest($testSuite); + } + } + + return $result; + } catch (FrameworkException $e) { + throw new RuntimeException( + $e->getMessage(), + $e->getCode(), + $e, + ); + } + } +} diff --git a/src/TextUI/Configuration/Xml/Validator/ValidationResult.php b/src/TextUI/Configuration/Xml/Validator/ValidationResult.php new file mode 100644 index 00000000000..95fe473d686 --- /dev/null +++ b/src/TextUI/Configuration/Xml/Validator/ValidationResult.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const PHP_EOL; +use function sprintf; +use function trim; +use LibXMLError; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class ValidationResult +{ + /** + * @var array> + */ + private array $validationErrors; + + /** + * @param array $errors + */ + public static function fromArray(array $errors): self + { + $validationErrors = []; + + foreach ($errors as $error) { + if (!isset($validationErrors[$error->line])) { + $validationErrors[$error->line] = []; + } + + $validationErrors[$error->line][] = trim($error->message); + } + + return new self($validationErrors); + } + + /** + * @param array> $validationErrors + */ + private function __construct(array $validationErrors) + { + $this->validationErrors = $validationErrors; + } + + public function hasValidationErrors(): bool + { + return $this->validationErrors !== []; + } + + public function asString(): string + { + $buffer = ''; + + foreach ($this->validationErrors as $line => $validationErrorsOnLine) { + $buffer .= sprintf(PHP_EOL . ' Line %d:' . PHP_EOL, $line); + + foreach ($validationErrorsOnLine as $validationError) { + $buffer .= sprintf(' - %s' . PHP_EOL, $validationError); + } + } + + return $buffer; + } +} diff --git a/src/TextUI/Configuration/Xml/Validator/Validator.php b/src/TextUI/Configuration/Xml/Validator/Validator.php new file mode 100644 index 00000000000..cc3a93dd29d --- /dev/null +++ b/src/TextUI/Configuration/Xml/Validator/Validator.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function assert; +use function file_get_contents; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use DOMDocument; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Validator +{ + public function validate(DOMDocument $document, string $xsdFilename): ValidationResult + { + $buffer = file_get_contents($xsdFilename); + + assert($buffer !== false); + + $originalErrorHandling = libxml_use_internal_errors(true); + + $document->schemaValidateSource($buffer); + + $errors = libxml_get_errors(); + libxml_clear_errors(); + libxml_use_internal_errors($originalErrorHandling); + + return ValidationResult::fromArray($errors); + } +} diff --git a/src/TextUI/Exception/CannotOpenSocketException.php b/src/TextUI/Exception/CannotOpenSocketException.php new file mode 100644 index 00000000000..519d1378568 --- /dev/null +++ b/src/TextUI/Exception/CannotOpenSocketException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class CannotOpenSocketException extends RuntimeException implements Exception +{ + public function __construct(string $hostname, int $port) + { + parent::__construct( + sprintf( + 'Cannot open socket %s:%d', + $hostname, + $port, + ), + ); + } +} diff --git a/src/TextUI/Exception/Exception.php b/src/TextUI/Exception/Exception.php new file mode 100644 index 00000000000..6b370ca0760 --- /dev/null +++ b/src/TextUI/Exception/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} diff --git a/src/TextUI/Exception/InvalidSocketException.php b/src/TextUI/Exception/InvalidSocketException.php new file mode 100644 index 00000000000..441afd2a1ed --- /dev/null +++ b/src/TextUI/Exception/InvalidSocketException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidSocketException extends RuntimeException implements Exception +{ + public function __construct(string $socket) + { + parent::__construct( + sprintf( + '"%s" does not match "socket://hostname:port" format', + $socket, + ), + ); + } +} diff --git a/src/TextUI/Exception/RuntimeException.php b/src/TextUI/Exception/RuntimeException.php new file mode 100644 index 00000000000..875a0487c8c --- /dev/null +++ b/src/TextUI/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class RuntimeException extends \RuntimeException implements Exception +{ +} diff --git a/src/TextUI/Exception/TestDirectoryNotFoundException.php b/src/TextUI/Exception/TestDirectoryNotFoundException.php new file mode 100644 index 00000000000..9b35390cdab --- /dev/null +++ b/src/TextUI/Exception/TestDirectoryNotFoundException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestDirectoryNotFoundException extends RuntimeException implements Exception +{ + public function __construct(string $path) + { + parent::__construct( + sprintf( + 'Test directory "%s" not found', + $path, + ), + ); + } +} diff --git a/src/TextUI/Exception/TestFileNotFoundException.php b/src/TextUI/Exception/TestFileNotFoundException.php new file mode 100644 index 00000000000..46c9df80671 --- /dev/null +++ b/src/TextUI/Exception/TestFileNotFoundException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestFileNotFoundException extends RuntimeException implements Exception +{ + public function __construct(string $path) + { + parent::__construct( + sprintf( + 'Test file "%s" not found', + $path, + ), + ); + } +} diff --git a/src/TextUI/Help.php b/src/TextUI/Help.php new file mode 100644 index 00000000000..209f22ea236 --- /dev/null +++ b/src/TextUI/Help.php @@ -0,0 +1,332 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use const PHP_EOL; +use function count; +use function defined; +use function explode; +use function max; +use function preg_replace_callback; +use function str_pad; +use function str_repeat; +use function strlen; +use function wordwrap; +use PHPUnit\Util\Color; +use SebastianBergmann\Environment\Console; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Help +{ + private const string LEFT_MARGIN = ' '; + private int $lengthOfLongestOptionName = 0; + private readonly int $columnsAvailableForDescription; + private bool $hasColor; + + public function __construct(?int $width = null, ?bool $withColor = null) + { + if ($width === null) { + $width = (new Console)->getNumberOfColumns(); + } + + if ($withColor === null) { + $this->hasColor = (new Console)->hasColorSupport(); + } else { + $this->hasColor = $withColor; + } + + foreach ($this->elements() as $options) { + foreach ($options as $option) { + if (isset($option['arg'])) { + $this->lengthOfLongestOptionName = max($this->lengthOfLongestOptionName, strlen($option['arg'])); + } + } + } + + $this->columnsAvailableForDescription = $width - $this->lengthOfLongestOptionName - 4; + } + + public function generate(): string + { + if ($this->hasColor) { + return $this->writeWithColor(); + } + + return $this->writeWithoutColor(); + } + + private function writeWithoutColor(): string + { + $buffer = ''; + + foreach ($this->elements() as $section => $options) { + $buffer .= "{$section}:" . PHP_EOL; + + if ($section !== 'Usage') { + $buffer .= PHP_EOL; + } + + foreach ($options as $option) { + if (isset($option['spacer'])) { + $buffer .= PHP_EOL; + } + + if (isset($option['text'])) { + $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; + } + + if (isset($option['arg'])) { + $arg = str_pad($option['arg'], $this->lengthOfLongestOptionName); + + $buffer .= self::LEFT_MARGIN . $arg . ' ' . $option['desc'] . PHP_EOL; + } + } + + $buffer .= PHP_EOL; + } + + return $buffer; + } + + private function writeWithColor(): string + { + $buffer = ''; + + foreach ($this->elements() as $section => $options) { + $buffer .= Color::colorize('fg-yellow', "{$section}:") . PHP_EOL; + + if ($section !== 'Usage') { + $buffer .= PHP_EOL; + } + + foreach ($options as $option) { + if (isset($option['spacer'])) { + $buffer .= PHP_EOL; + } + + if (isset($option['text'])) { + $buffer .= self::LEFT_MARGIN . $option['text'] . PHP_EOL; + } + + if (isset($option['arg'])) { + $arg = Color::colorize('fg-green', str_pad($option['arg'], $this->lengthOfLongestOptionName)); + $arg = preg_replace_callback( + '/(<[^>]+>)/', + static fn (array $matches) => Color::colorize('fg-cyan', $matches[0]), + $arg, + ); + + $desc = explode(PHP_EOL, wordwrap($option['desc'], $this->columnsAvailableForDescription, PHP_EOL)); + + $buffer .= self::LEFT_MARGIN . $arg . ' ' . $desc[0] . PHP_EOL; + + for ($i = 1; $i < count($desc); $i++) { + $buffer .= str_repeat(' ', $this->lengthOfLongestOptionName + 3) . $desc[$i] . PHP_EOL; + } + } + } + + $buffer .= PHP_EOL; + } + + return $buffer; + } + + /** + * @return array> + */ + private function elements(): array + { + $elements = [ + 'Usage' => [ + ['text' => 'phpunit [options] ...'], + ], + + 'Configuration' => [ + ['arg' => '--bootstrap ', 'desc' => 'A PHP script that is included before the tests run'], + ['arg' => '-c|--configuration ', 'desc' => 'Read configuration from XML file'], + ['arg' => '--no-configuration', 'desc' => 'Ignore default configuration file (phpunit.xml)'], + ['arg' => '--extension ', 'desc' => 'Register test runner extension with bootstrap '], + ['arg' => '--no-extensions', 'desc' => 'Do not register test runner extensions'], + ['arg' => '--include-path ', 'desc' => 'Prepend PHP\'s include_path with given path(s)'], + ['arg' => '-d ', 'desc' => 'Sets a php.ini value'], + ['arg' => '--cache-directory ', 'desc' => 'Specify cache directory'], + ['arg' => '--generate-configuration', 'desc' => 'Generate configuration file with suggested settings'], + ['arg' => '--migrate-configuration', 'desc' => 'Migrate configuration file to current format'], + ['arg' => '--generate-baseline ', 'desc' => 'Generate baseline for issues'], + ['arg' => '--use-baseline ', 'desc' => 'Use baseline to ignore issues'], + ['arg' => '--ignore-baseline', 'desc' => 'Do not use baseline to ignore issues'], + ], + + 'Selection' => [ + ['arg' => '--all', 'desc' => 'Ignore test selection from XML configuration file'], + ['arg' => '--list-suites', 'desc' => 'List available test suites'], + ['arg' => '--testsuite ', 'desc' => 'Only run tests from the specified test suite(s)'], + ['arg' => '--exclude-testsuite ', 'desc' => 'Exclude tests from the specified test suite(s)'], + ['arg' => '--list-groups', 'desc' => 'List available test groups'], + ['arg' => '--group ', 'desc' => 'Only run tests from the specified group(s)'], + ['arg' => '--exclude-group ', 'desc' => 'Exclude tests from the specified group(s)'], + ['arg' => '--covers ', 'desc' => 'Only run tests that intend to cover '], + ['arg' => '--uses ', 'desc' => 'Only run tests that intend to use '], + ['arg' => '--requires-php-extension ', 'desc' => 'Only run tests that require PHP extension '], + ['arg' => '--list-test-files', 'desc' => 'List available test files'], + ['arg' => '--list-tests', 'desc' => 'List available tests'], + ['arg' => '--list-tests-xml ', 'desc' => 'List available tests in XML format'], + ['arg' => '--filter ', 'desc' => 'Filter which tests to run'], + ['arg' => '--exclude-filter ', 'desc' => 'Exclude tests for the specified filter pattern'], + ['arg' => '--test-suffix ', 'desc' => 'Only search for test in files with specified suffix(es). Default: Test.php,.phpt'], + ], + + 'Execution' => [ + ['arg' => '--process-isolation', 'desc' => 'Run each test in a separate PHP process'], + ['arg' => '--globals-backup', 'desc' => 'Backup and restore $GLOBALS for each test'], + ['arg' => '--static-backup', 'desc' => 'Backup and restore static properties for each test'], + ['spacer' => ''], + + ['arg' => '--strict-coverage', 'desc' => 'Be strict about code coverage metadata'], + ['arg' => '--strict-global-state', 'desc' => 'Be strict about changes to global state'], + ['arg' => '--disallow-test-output', 'desc' => 'Be strict about output during tests'], + ['arg' => '--enforce-time-limit', 'desc' => 'Enforce time limit based on test size'], + ['arg' => '--default-time-limit ', 'desc' => 'Timeout in seconds for tests that have no declared size'], + ['arg' => '--do-not-report-useless-tests', 'desc' => 'Do not report tests that do not test anything'], + ['spacer' => ''], + + ['arg' => '--stop-on-defect', 'desc' => 'Stop after first error, failure, warning, or risky test'], + ['arg' => '--stop-on-error', 'desc' => 'Stop after first error'], + ['arg' => '--stop-on-failure', 'desc' => 'Stop after first failure'], + ['arg' => '--stop-on-warning', 'desc' => 'Stop after first warning'], + ['arg' => '--stop-on-risky', 'desc' => 'Stop after first risky test'], + ['arg' => '--stop-on-deprecation', 'desc' => 'Stop after first test that triggered a deprecation'], + ['arg' => '--stop-on-notice', 'desc' => 'Stop after first test that triggered a notice'], + ['arg' => '--stop-on-skipped', 'desc' => 'Stop after first skipped test'], + ['arg' => '--stop-on-incomplete', 'desc' => 'Stop after first incomplete test'], + ['spacer' => ''], + + ['arg' => '--fail-on-empty-test-suite', 'desc' => 'Signal failure using shell exit code when no tests were run'], + ['arg' => '--fail-on-warning', 'desc' => 'Signal failure using shell exit code when a warning was triggered'], + ['arg' => '--fail-on-risky', 'desc' => 'Signal failure using shell exit code when a test was considered risky'], + ['arg' => '--fail-on-deprecation', 'desc' => 'Signal failure using shell exit code when a deprecation was triggered'], + ['arg' => '--fail-on-phpunit-deprecation', 'desc' => 'Signal failure using shell exit code when a PHPUnit deprecation was triggered'], + ['arg' => '--fail-on-phpunit-notice', 'desc' => 'Signal failure using shell exit code when a PHPUnit notice was triggered'], + ['arg' => '--fail-on-phpunit-warning', 'desc' => 'Signal failure using shell exit code when a PHPUnit warning was triggered'], + ['arg' => '--fail-on-notice', 'desc' => 'Signal failure using shell exit code when a notice was triggered'], + ['arg' => '--fail-on-skipped', 'desc' => 'Signal failure using shell exit code when a test was skipped'], + ['arg' => '--fail-on-incomplete', 'desc' => 'Signal failure using shell exit code when a test was marked incomplete'], + ['arg' => '--fail-on-all-issues', 'desc' => 'Signal failure using shell exit code when an issue is triggered'], + ['spacer' => ''], + + ['arg' => '--do-not-fail-on-empty-test-suite', 'desc' => 'Do not signal failure using shell exit code when no tests were run'], + ['arg' => '--do-not-fail-on-warning', 'desc' => 'Do not signal failure using shell exit code when a warning was triggered'], + ['arg' => '--do-not-fail-on-risky', 'desc' => 'Do not signal failure using shell exit code when a test was considered risky'], + ['arg' => '--do-not-fail-on-deprecation', 'desc' => 'Do not signal failure using shell exit code when a deprecation was triggered'], + ['arg' => '--do-not-fail-on-phpunit-deprecation', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit deprecation was triggered'], + ['arg' => '--do-not-fail-on-phpunit-notice', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit notice was triggered'], + ['arg' => '--do-not-fail-on-phpunit-warning', 'desc' => 'Do not signal failure using shell exit code when a PHPUnit warning was triggered'], + ['arg' => '--do-not-fail-on-notice', 'desc' => 'Do not signal failure using shell exit code when a notice was triggered'], + ['arg' => '--do-not-fail-on-skipped', 'desc' => 'Do not signal failure using shell exit code when a test was skipped'], + ['arg' => '--do-not-fail-on-incomplete', 'desc' => 'Do not signal failure using shell exit code when a test was marked incomplete'], + ['spacer' => ''], + + ['arg' => '--cache-result', 'desc' => 'Write test results to cache file'], + ['arg' => '--do-not-cache-result', 'desc' => 'Do not write test results to cache file'], + ['spacer' => ''], + + ['arg' => '--order-by ', 'desc' => 'Run tests in order: default|defects|depends|duration|no-depends|random|reverse|size'], + ['arg' => '--random-order-seed ', 'desc' => 'Use the specified random seed when running tests in random order'], + ], + + 'Reporting' => [ + ['arg' => '--colors ', 'desc' => 'Use colors in output ("never", "auto" or "always")'], + ['arg' => '--columns ', 'desc' => 'Number of columns to use for progress output'], + ['arg' => '--columns max', 'desc' => 'Use maximum number of columns for progress output'], + ['arg' => '--stderr', 'desc' => 'Write to STDERR instead of STDOUT'], + ['spacer' => ''], + + ['arg' => '--no-progress', 'desc' => 'Disable output of test execution progress'], + ['arg' => '--no-results', 'desc' => 'Disable output of test results'], + ['arg' => '--no-output', 'desc' => 'Disable all output'], + ['spacer' => ''], + + ['arg' => '--display-incomplete', 'desc' => 'Display details for incomplete tests'], + ['arg' => '--display-skipped', 'desc' => 'Display details for skipped tests'], + ['arg' => '--display-deprecations', 'desc' => 'Display details for deprecations triggered by tests'], + ['arg' => '--display-phpunit-deprecations', 'desc' => 'Display details for PHPUnit deprecations'], + ['arg' => '--display-phpunit-notices', 'desc' => 'Display details for PHPUnit notices'], + ['arg' => '--display-errors', 'desc' => 'Display details for errors triggered by tests'], + ['arg' => '--display-notices', 'desc' => 'Display details for notices triggered by tests'], + ['arg' => '--display-warnings', 'desc' => 'Display details for warnings triggered by tests'], + ['arg' => '--display-all-issues', 'desc' => 'Display details for all issues that are triggered'], + ['arg' => '--reverse-list', 'desc' => 'Print defects in reverse order'], + ['spacer' => ''], + + ['arg' => '--teamcity', 'desc' => 'Replace default progress and result output with TeamCity format'], + ['arg' => '--testdox', 'desc' => 'Replace default result output with TestDox format'], + ['arg' => '--testdox-summary', 'desc' => 'Repeat TestDox output for tests with errors, failures, or issues'], + ['spacer' => ''], + + ['arg' => '--debug', 'desc' => 'Replace default progress and result output with debugging information'], + ['arg' => '--with-telemetry', 'desc' => 'Include telemetry information in debugging information output'], + ], + + 'Logging' => [ + ['arg' => '--log-junit ', 'desc' => 'Write test results in JUnit XML format to file'], + ['arg' => '--log-otr ', 'desc' => 'Write test results in Open Test Reporting XML format to file'], + ['arg' => '--include-git-information', 'desc' => 'Include Git information in Open Test Reporting XML logfile'], + ['arg' => '--log-teamcity ', 'desc' => 'Write test results in TeamCity format to file'], + ['arg' => '--testdox-html ', 'desc' => 'Write test results in TestDox format (HTML) to file'], + ['arg' => '--testdox-text ', 'desc' => 'Write test results in TestDox format (plain text) to file'], + ['arg' => '--log-events-text ', 'desc' => 'Stream events as plain text to file'], + ['arg' => '--log-events-verbose-text ', 'desc' => 'Stream events as plain text with extended information to file'], + ['arg' => '--no-logging', 'desc' => 'Ignore logging configured in the XML configuration file'], + ], + + 'Code Coverage' => [ + ['arg' => '--coverage-clover ', 'desc' => 'Write code coverage report in Clover XML format to file'], + ['arg' => '--coverage-openclover ', 'desc' => 'Write code coverage report in OpenClover XML format to file'], + ['arg' => '--coverage-cobertura ', 'desc' => 'Write code coverage report in Cobertura XML format to file'], + ['arg' => '--coverage-crap4j ', 'desc' => 'Write code coverage report in Crap4J XML format to file'], + ['arg' => '--coverage-html ', 'desc' => 'Write code coverage report in HTML format to directory'], + ['arg' => '--coverage-php ', 'desc' => 'Write serialized code coverage data to file'], + ['arg' => '--coverage-text=', 'desc' => 'Write code coverage report in text format to file [default: standard output]'], + ['arg' => '--only-summary-for-coverage-text', 'desc' => 'Option for code coverage report in text format: only show summary'], + ['arg' => '--show-uncovered-for-coverage-text', 'desc' => 'Option for code coverage report in text format: show uncovered files'], + ['arg' => '--coverage-xml ', 'desc' => 'Write code coverage report in XML format to directory'], + ['arg' => '--exclude-source-from-xml-coverage', 'desc' => 'Exclude element from code coverage report in XML format'], + ['arg' => '--warm-coverage-cache', 'desc' => 'Warm static analysis cache'], + ['arg' => '--coverage-filter ', 'desc' => 'Include in code coverage reporting'], + ['arg' => '--path-coverage', 'desc' => 'Report path coverage in addition to line coverage'], + ['arg' => '--disable-coverage-ignore', 'desc' => 'Disable metadata for ignoring code coverage'], + ['arg' => '--no-coverage', 'desc' => 'Ignore code coverage reporting configured in the XML configuration file'], + ], + ]; + + if (defined('__PHPUNIT_PHAR__')) { + $elements['PHAR'] = [ + ['arg' => '--manifest', 'desc' => 'Print Software Bill of Materials (SBOM) in plain-text format'], + ['arg' => '--sbom', 'desc' => 'Print Software Bill of Materials (SBOM) in CycloneDX XML format'], + ['arg' => '--composer-lock', 'desc' => 'Print composer.lock file used to build the PHAR'], + ]; + } + + $elements['Miscellaneous'] = [ + ['arg' => '-h|--help', 'desc' => 'Prints this usage information'], + ['arg' => '--version', 'desc' => 'Prints the version and exits'], + ['arg' => '--atleast-version ', 'desc' => 'Checks that version is greater than and exits'], + ['arg' => '--check-version', 'desc' => 'Checks whether PHPUnit is the latest version and exits'], + ['arg' => '--check-php-configuration', 'desc' => 'Checks whether PHP configuration follows best practices'], + ]; + + return $elements; + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php b/src/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php new file mode 100644 index 00000000000..de8daf9bd7a --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/ProgressPrinter.php @@ -0,0 +1,424 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use function floor; +use function sprintf; +use function str_repeat; +use function strlen; +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\TestRunner\ChildProcessErrored; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\TextUI\Configuration\Source; +use PHPUnit\TextUI\Configuration\SourceFilter; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Color; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ProgressPrinter +{ + private readonly Printer $printer; + private readonly bool $colors; + private readonly int $numberOfColumns; + private readonly Source $source; + private int $column = 0; + private int $numberOfTests = 0; + private int $numberOfTestsWidth = 0; + private int $maxColumn = 0; + private int $numberOfTestsRun = 0; + private ?TestStatus $status = null; + private bool $prepared = false; + private bool $childProcessErrored = false; + + public function __construct(Printer $printer, Facade $facade, bool $colors, int $numberOfColumns, Source $source) + { + $this->printer = $printer; + $this->colors = $colors; + $this->numberOfColumns = $numberOfColumns; + $this->source = $source; + + $this->registerSubscribers($facade); + } + + public function testRunnerExecutionStarted(ExecutionStarted $event): void + { + $this->numberOfTestsRun = 0; + $this->numberOfTests = $event->testSuite()->count(); + $this->numberOfTestsWidth = strlen((string) $this->numberOfTests); + $this->column = 0; + $this->maxColumn = $this->numberOfColumns - strlen(' / (XXX%)') - (2 * $this->numberOfTestsWidth); + } + + public function beforeTestClassMethodErrored(): void + { + $this->printProgressForError(); + $this->updateTestStatus(TestStatus::error()); + } + + public function testPrepared(): void + { + $this->prepared = true; + } + + public function testSkipped(): void + { + if (!$this->prepared) { + $this->printProgressForSkipped(); + } else { + $this->updateTestStatus(TestStatus::skipped()); + } + } + + public function testMarkedIncomplete(): void + { + $this->updateTestStatus(TestStatus::incomplete()); + } + + public function testTriggeredNotice(NoticeTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + + if ($this->source->restrictNotices() && + !SourceFilter::instance()->includes($event->file())) { + return; + } + + if (!$this->source->ignoreSuppressionOfNotices() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::notice()); + } + + public function testTriggeredPhpNotice(PhpNoticeTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + + if ($this->source->restrictNotices() && + !SourceFilter::instance()->includes($event->file())) { + return; + } + + if (!$this->source->ignoreSuppressionOfPhpNotices() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::notice()); + } + + public function testTriggeredDeprecation(DeprecationTriggered $event): void + { + if ($event->ignoredByBaseline() || $event->ignoredByTest()) { + return; + } + + if ($this->source->ignoreSelfDeprecations() && + ($event->trigger()->isTest() || $event->trigger()->isSelf())) { + return; + } + + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return; + } + + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return; + } + + if (!$this->source->ignoreSuppressionOfDeprecations() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredPhpDeprecation(PhpDeprecationTriggered $event): void + { + if ($event->ignoredByBaseline() || $event->ignoredByTest()) { + return; + } + + if ($this->source->ignoreSelfDeprecations() && + ($event->trigger()->isTest() || $event->trigger()->isSelf())) { + return; + } + + if ($this->source->ignoreDirectDeprecations() && $event->trigger()->isDirect()) { + return; + } + + if ($this->source->ignoreIndirectDeprecations() && $event->trigger()->isIndirect()) { + return; + } + + if (!$this->source->ignoreSuppressionOfPhpDeprecations() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredPhpunitDeprecation(): void + { + $this->updateTestStatus(TestStatus::deprecation()); + } + + public function testTriggeredPhpunitNotice(): void + { + $this->updateTestStatus(TestStatus::notice()); + } + + public function testConsideredRisky(): void + { + $this->updateTestStatus(TestStatus::risky()); + } + + public function testTriggeredWarning(WarningTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + + if ($this->source->restrictWarnings() && + !SourceFilter::instance()->includes($event->file())) { + return; + } + + if (!$this->source->ignoreSuppressionOfWarnings() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + public function testTriggeredPhpWarning(PhpWarningTriggered $event): void + { + if ($event->ignoredByBaseline()) { + return; + } + + if ($this->source->restrictWarnings() && + !SourceFilter::instance()->includes($event->file())) { + return; + } + + if (!$this->source->ignoreSuppressionOfPhpWarnings() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + public function testTriggeredPhpunitWarning(PhpunitWarningTriggered $event): void + { + if ($event->ignoredByTest()) { + return; + } + + $this->updateTestStatus(TestStatus::warning()); + } + + public function testTriggeredError(ErrorTriggered $event): void + { + if (!$this->source->ignoreSuppressionOfErrors() && $event->wasSuppressed()) { + return; + } + + $this->updateTestStatus(TestStatus::error()); + } + + public function testFailed(): void + { + $this->updateTestStatus(TestStatus::failure()); + } + + public function testErrored(Errored $event): void + { + if ($this->childProcessErrored) { + $this->updateTestStatus(TestStatus::error()); + + return; + } + + if (!$this->prepared) { + $this->printProgressForError(); + } else { + $this->updateTestStatus(TestStatus::error()); + } + } + + public function testFinished(): void + { + if ($this->status === null) { + $this->printProgressForSuccess(); + } elseif ($this->status->isSkipped()) { + $this->printProgressForSkipped(); + } elseif ($this->status->isIncomplete()) { + $this->printProgressForIncomplete(); + } elseif ($this->status->isRisky()) { + $this->printProgressForRisky(); + } elseif ($this->status->isNotice()) { + $this->printProgressForNotice(); + } elseif ($this->status->isDeprecation()) { + $this->printProgressForDeprecation(); + } elseif ($this->status->isWarning()) { + $this->printProgressForWarning(); + } elseif ($this->status->isFailure()) { + $this->printProgressForFailure(); + } else { + $this->printProgressForError(); + } + + $this->status = null; + $this->prepared = false; + $this->childProcessErrored = false; + } + + public function childProcessErrored(ChildProcessErrored $event): void + { + $this->childProcessErrored = true; + } + + private function registerSubscribers(Facade $facade): void + { + $facade->registerSubscribers( + new BeforeTestClassMethodErroredSubscriber($this), + new TestConsideredRiskySubscriber($this), + new TestErroredSubscriber($this), + new TestFailedSubscriber($this), + new TestFinishedSubscriber($this), + new TestMarkedIncompleteSubscriber($this), + new TestPreparedSubscriber($this), + new TestRunnerExecutionStartedSubscriber($this), + new TestSkippedSubscriber($this), + new TestTriggeredDeprecationSubscriber($this), + new TestTriggeredNoticeSubscriber($this), + new TestTriggeredPhpDeprecationSubscriber($this), + new TestTriggeredPhpNoticeSubscriber($this), + new TestTriggeredPhpunitDeprecationSubscriber($this), + new TestTriggeredPhpunitNoticeSubscriber($this), + new TestTriggeredPhpunitWarningSubscriber($this), + new TestTriggeredPhpWarningSubscriber($this), + new TestTriggeredWarningSubscriber($this), + new ChildProcessErroredSubscriber($this), + ); + } + + private function updateTestStatus(TestStatus $status): void + { + if ($this->status !== null && + $this->status->isMoreImportantThan($status)) { + return; + } + + $this->status = $status; + } + + private function printProgressForSuccess(): void + { + $this->printProgress('.'); + } + + private function printProgressForSkipped(): void + { + $this->printProgressWithColor('fg-cyan, bold', 'S'); + } + + private function printProgressForIncomplete(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'I'); + } + + private function printProgressForNotice(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'N'); + } + + private function printProgressForDeprecation(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'D'); + } + + private function printProgressForRisky(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'R'); + } + + private function printProgressForWarning(): void + { + $this->printProgressWithColor('fg-yellow, bold', 'W'); + } + + private function printProgressForFailure(): void + { + $this->printProgressWithColor('bg-red, fg-white', 'F'); + } + + private function printProgressForError(): void + { + $this->printProgressWithColor('fg-red, bold', 'E'); + } + + private function printProgressWithColor(string $color, string $progress): void + { + if ($this->colors) { + $progress = Color::colorizeTextBox($color, $progress); + } + + $this->printProgress($progress); + } + + private function printProgress(string $progress): void + { + $this->printer->print($progress); + + $this->column++; + $this->numberOfTestsRun++; + + if ($this->column === $this->maxColumn || $this->numberOfTestsRun === $this->numberOfTests) { + if ($this->numberOfTestsRun === $this->numberOfTests) { + $this->printer->print(str_repeat(' ', $this->maxColumn - $this->column)); + } + + $this->printer->print( + sprintf( + ' %' . $this->numberOfTestsWidth . 'd / %' . + $this->numberOfTestsWidth . 'd (%3s%%)', + $this->numberOfTestsRun, + $this->numberOfTests, + floor(($this->numberOfTestsRun / $this->numberOfTests) * 100), + ), + ); + + if ($this->column === $this->maxColumn) { + $this->column = 0; + $this->printer->print("\n"); + } + } + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php new file mode 100644 index 00000000000..2984cdda8b7 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/BeforeTestClassMethodErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class BeforeTestClassMethodErroredSubscriber extends Subscriber implements BeforeFirstTestMethodErroredSubscriber +{ + public function notify(BeforeFirstTestMethodErrored $event): void + { + $this->printer()->beforeTestClassMethodErrored(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php new file mode 100644 index 00000000000..643694076e8 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/ChildProcessErroredSubscriber.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\TestRunner\ChildProcessErrored; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ChildProcessErroredSubscriber extends Subscriber implements \PHPUnit\Event\TestRunner\ChildProcessErroredSubscriber +{ + public function notify(ChildProcessErrored $event): void + { + $this->printer()->childProcessErrored($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php new file mode 100644 index 00000000000..32515ee343c --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/Subscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class Subscriber +{ + private ProgressPrinter $printer; + + public function __construct(ProgressPrinter $printer) + { + $this->printer = $printer; + } + + protected function printer(): ProgressPrinter + { + return $this->printer; + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php new file mode 100644 index 00000000000..e5b57c6d3d6 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestConsideredRiskySubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\ConsideredRiskySubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestConsideredRiskySubscriber extends Subscriber implements ConsideredRiskySubscriber +{ + public function notify(ConsideredRisky $event): void + { + $this->printer()->testConsideredRisky(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php new file mode 100644 index 00000000000..33340755261 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestErroredSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\ErroredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestErroredSubscriber extends Subscriber implements ErroredSubscriber +{ + public function notify(Errored $event): void + { + $this->printer()->testErrored($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php new file mode 100644 index 00000000000..9109d1b312b --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFailedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\FailedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFailedSubscriber extends Subscriber implements FailedSubscriber +{ + public function notify(Failed $event): void + { + $this->printer()->testFailed(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php new file mode 100644 index 00000000000..e4b4ca5ee87 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestFinishedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Finished; +use PHPUnit\Event\Test\FinishedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestFinishedSubscriber extends Subscriber implements FinishedSubscriber +{ + public function notify(Finished $event): void + { + $this->printer()->testFinished(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php new file mode 100644 index 00000000000..8b445088064 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestMarkedIncompleteSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\MarkedIncompleteSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestMarkedIncompleteSubscriber extends Subscriber implements MarkedIncompleteSubscriber +{ + public function notify(MarkedIncomplete $event): void + { + $this->printer()->testMarkedIncomplete(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php new file mode 100644 index 00000000000..d99f2fa4190 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestPreparedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Prepared; +use PHPUnit\Event\Test\PreparedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestPreparedSubscriber extends Subscriber implements PreparedSubscriber +{ + public function notify(Prepared $event): void + { + $this->printer()->testPrepared(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php new file mode 100644 index 00000000000..78e104f6d46 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestRunnerExecutionStartedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestRunnerExecutionStartedSubscriber extends Subscriber implements ExecutionStartedSubscriber +{ + public function notify(ExecutionStarted $event): void + { + $this->printer()->testRunnerExecutionStarted($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php new file mode 100644 index 00000000000..a2f4e25569b --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestSkippedSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\Skipped; +use PHPUnit\Event\Test\SkippedSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSkippedSubscriber extends Subscriber implements SkippedSubscriber +{ + public function notify(Skipped $event): void + { + $this->printer()->testSkipped(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php new file mode 100644 index 00000000000..16a4ccf96ec --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\DeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredDeprecationSubscriber extends Subscriber implements DeprecationTriggeredSubscriber +{ + public function notify(DeprecationTriggered $event): void + { + $this->printer()->testTriggeredDeprecation($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php new file mode 100644 index 00000000000..1f89911b45e --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredErrorSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\ErrorTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredErrorSubscriber extends Subscriber implements ErrorTriggeredSubscriber +{ + public function notify(ErrorTriggered $event): void + { + $this->printer()->testTriggeredError($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php new file mode 100644 index 00000000000..0639f027272 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\NoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredNoticeSubscriber extends Subscriber implements NoticeTriggeredSubscriber +{ + public function notify(NoticeTriggered $event): void + { + $this->printer()->testTriggeredNotice($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php new file mode 100644 index 00000000000..550250c2100 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpDeprecationSubscriber extends Subscriber implements PhpDeprecationTriggeredSubscriber +{ + public function notify(PhpDeprecationTriggered $event): void + { + $this->printer()->testTriggeredPhpDeprecation($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php new file mode 100644 index 00000000000..299b898c076 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpNoticeSubscriber extends Subscriber implements PhpNoticeTriggeredSubscriber +{ + public function notify(PhpNoticeTriggered $event): void + { + $this->printer()->testTriggeredPhpNotice($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php new file mode 100644 index 00000000000..a4ff81c2276 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpWarningSubscriber extends Subscriber implements PhpWarningTriggeredSubscriber +{ + public function notify(PhpWarningTriggered $event): void + { + $this->printer()->testTriggeredPhpWarning($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php new file mode 100644 index 00000000000..62311a0123a --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitDeprecationSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitDeprecationSubscriber extends Subscriber implements PhpunitDeprecationTriggeredSubscriber +{ + public function notify(PhpunitDeprecationTriggered $event): void + { + $this->printer()->testTriggeredPhpunitDeprecation(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php new file mode 100644 index 00000000000..6b0e48cfd1b --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitNoticeSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitNoticeSubscriber extends Subscriber implements PhpunitNoticeTriggeredSubscriber +{ + public function notify(PhpunitNoticeTriggered $event): void + { + $this->printer()->testTriggeredPhpunitNotice(); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php new file mode 100644 index 00000000000..7d0aed1ff87 --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredPhpunitWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredPhpunitWarningSubscriber extends Subscriber implements PhpunitWarningTriggeredSubscriber +{ + public function notify(PhpunitWarningTriggered $event): void + { + $this->printer()->testTriggeredPhpunitWarning($event); + } +} diff --git a/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php new file mode 100644 index 00000000000..620458422dd --- /dev/null +++ b/src/TextUI/Output/Default/ProgressPrinter/Subscriber/TestTriggeredWarningSubscriber.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default\ProgressPrinter; + +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\Event\Test\WarningTriggeredSubscriber; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestTriggeredWarningSubscriber extends Subscriber implements WarningTriggeredSubscriber +{ + public function notify(WarningTriggered $event): void + { + $this->printer()->testTriggeredWarning($event); + } +} diff --git a/src/TextUI/Output/Default/ResultPrinter.php b/src/TextUI/Output/Default/ResultPrinter.php new file mode 100644 index 00000000000..555382db45f --- /dev/null +++ b/src/TextUI/Output/Default/ResultPrinter.php @@ -0,0 +1,696 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use const PHP_EOL; +use function array_keys; +use function array_merge; +use function array_reverse; +use function array_unique; +use function assert; +use function count; +use function explode; +use function ksort; +use function range; +use function sprintf; +use function str_starts_with; +use function strlen; +use function substr; +use function trim; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\DeprecationTriggered; +use PHPUnit\Event\Test\ErrorTriggered; +use PHPUnit\Event\Test\NoticeTriggered; +use PHPUnit\Event\Test\PhpDeprecationTriggered; +use PHPUnit\Event\Test\PhpNoticeTriggered; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\PhpWarningTriggered; +use PHPUnit\Event\Test\WarningTriggered; +use PHPUnit\TestRunner\TestResult\Issues\Issue; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class ResultPrinter +{ + private readonly Printer $printer; + private readonly bool $displayPhpunitDeprecations; + private readonly bool $displayPhpunitErrors; + private readonly bool $displayPhpunitNotices; + private readonly bool $displayPhpunitWarnings; + private readonly bool $displayTestsWithErrors; + private readonly bool $displayTestsWithFailedAssertions; + private readonly bool $displayRiskyTests; + private readonly bool $displayDetailsOnIncompleteTests; + private readonly bool $displayDetailsOnSkippedTests; + private readonly bool $displayDetailsOnTestsThatTriggerDeprecations; + private readonly bool $displayDetailsOnTestsThatTriggerErrors; + private readonly bool $displayDetailsOnTestsThatTriggerNotices; + private readonly bool $displayDetailsOnTestsThatTriggerWarnings; + private readonly bool $displayDefectsInReverseOrder; + private bool $listPrinted = false; + + public function __construct(Printer $printer, bool $displayPhpunitDeprecations, bool $displayPhpunitErrors, bool $displayPhpunitNotices, bool $displayPhpunitWarnings, bool $displayTestsWithErrors, bool $displayTestsWithFailedAssertions, bool $displayRiskyTests, bool $displayDetailsOnIncompleteTests, bool $displayDetailsOnSkippedTests, bool $displayDetailsOnTestsThatTriggerDeprecations, bool $displayDetailsOnTestsThatTriggerErrors, bool $displayDetailsOnTestsThatTriggerNotices, bool $displayDetailsOnTestsThatTriggerWarnings, bool $displayDefectsInReverseOrder) + { + $this->printer = $printer; + $this->displayPhpunitDeprecations = $displayPhpunitDeprecations; + $this->displayPhpunitErrors = $displayPhpunitErrors; + $this->displayPhpunitNotices = $displayPhpunitNotices; + $this->displayPhpunitWarnings = $displayPhpunitWarnings; + $this->displayTestsWithErrors = $displayTestsWithErrors; + $this->displayTestsWithFailedAssertions = $displayTestsWithFailedAssertions; + $this->displayRiskyTests = $displayRiskyTests; + $this->displayDetailsOnIncompleteTests = $displayDetailsOnIncompleteTests; + $this->displayDetailsOnSkippedTests = $displayDetailsOnSkippedTests; + $this->displayDetailsOnTestsThatTriggerDeprecations = $displayDetailsOnTestsThatTriggerDeprecations; + $this->displayDetailsOnTestsThatTriggerErrors = $displayDetailsOnTestsThatTriggerErrors; + $this->displayDetailsOnTestsThatTriggerNotices = $displayDetailsOnTestsThatTriggerNotices; + $this->displayDetailsOnTestsThatTriggerWarnings = $displayDetailsOnTestsThatTriggerWarnings; + $this->displayDefectsInReverseOrder = $displayDefectsInReverseOrder; + } + + public function print(TestResult $result, bool $stackTraceForDeprecations = false): void + { + if ($this->displayPhpunitErrors) { + $this->printPhpunitErrors($result); + } + + if ($this->displayPhpunitWarnings) { + $this->printTestRunnerWarnings($result); + } + + if ($this->displayPhpunitDeprecations) { + $this->printTestRunnerDeprecations($result); + } + + if ($this->displayPhpunitNotices) { + $this->printTestRunnerNotices($result); + } + + if ($this->displayTestsWithErrors) { + $this->printTestsWithErrors($result); + } + + if ($this->displayTestsWithFailedAssertions) { + $this->printTestsWithFailedAssertions($result); + } + + if ($this->displayPhpunitWarnings) { + $this->printDetailsOnTestsThatTriggeredPhpunitWarnings($result); + } + + if ($this->displayPhpunitDeprecations) { + $this->printDetailsOnTestsThatTriggeredPhpunitDeprecations($result); + } + + if ($this->displayRiskyTests) { + $this->printRiskyTests($result); + } + + if ($this->displayPhpunitNotices) { + $this->printDetailsOnTestsThatTriggeredPhpunitNotices($result); + } + + if ($this->displayDetailsOnIncompleteTests) { + $this->printIncompleteTests($result); + } + + if ($this->displayDetailsOnSkippedTests) { + $this->printSkippedTestSuites($result); + $this->printSkippedTests($result); + } + + if ($this->displayDetailsOnTestsThatTriggerErrors) { + $this->printIssueList('error', $result->errors()); + } + + if ($this->displayDetailsOnTestsThatTriggerWarnings) { + $this->printIssueList('PHP warning', $result->phpWarnings()); + $this->printIssueList('warning', $result->warnings()); + } + + if ($this->displayDetailsOnTestsThatTriggerNotices) { + $this->printIssueList('PHP notice', $result->phpNotices()); + $this->printIssueList('notice', $result->notices()); + } + + if ($this->displayDetailsOnTestsThatTriggerDeprecations) { + $this->printIssueList('PHP deprecation', $result->phpDeprecations()); + $this->printIssueList('deprecation', $result->deprecations(), $stackTraceForDeprecations); + } + } + + private function printPhpunitErrors(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitErrorEvents()) { + return; + } + + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitErrorEvents()); + + $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'PHPUnit error'); + $this->printList($elements['elements']); + } + + private function printDetailsOnTestsThatTriggeredPhpunitDeprecations(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitDeprecationEvents()) { + return; + } + + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitDeprecationEvents()); + + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues( + $elements['numberOfTestsWithIssues'], + $elements['numberOfIssues'], + 'PHPUnit deprecation', + ); + + $this->printList($elements['elements']); + } + + private function printDetailsOnTestsThatTriggeredPhpunitNotices(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitNoticeEvents()) { + return; + } + + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitNoticeEvents()); + + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues( + $elements['numberOfTestsWithIssues'], + $elements['numberOfIssues'], + 'PHPUnit notice', + ); + + $this->printList($elements['elements']); + } + + private function printTestRunnerNotices(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredNoticeEvents()) { + return; + } + + $elements = []; + $messages = []; + + foreach ($result->testRunnerTriggeredNoticeEvents() as $event) { + if (isset($messages[$event->message()])) { + continue; + } + + $elements[] = [ + 'title' => $event->message(), + 'body' => '', + ]; + + $messages[$event->message()] = true; + } + + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner notice'); + $this->printList($elements); + } + + private function printTestRunnerWarnings(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredWarningEvents()) { + return; + } + + $elements = []; + $messages = []; + + foreach ($result->testRunnerTriggeredWarningEvents() as $event) { + if (isset($messages[$event->message()])) { + continue; + } + + $elements[] = [ + 'title' => $event->message(), + 'body' => '', + ]; + + $messages[$event->message()] = true; + } + + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner warning'); + $this->printList($elements); + } + + private function printTestRunnerDeprecations(TestResult $result): void + { + if (!$result->hasTestRunnerTriggeredDeprecationEvents()) { + return; + } + + $elements = []; + + foreach ($result->testRunnerTriggeredDeprecationEvents() as $event) { + $elements[] = [ + 'title' => $event->message(), + 'body' => '', + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'PHPUnit test runner deprecation'); + $this->printList($elements); + } + + private function printDetailsOnTestsThatTriggeredPhpunitWarnings(TestResult $result): void + { + if (!$result->hasTestTriggeredPhpunitWarningEvents()) { + return; + } + + $elements = $this->mapTestsWithIssuesEventsToElements($result->testTriggeredPhpunitWarningEvents()); + + $this->printListHeaderWithNumberOfTestsAndNumberOfIssues( + $elements['numberOfTestsWithIssues'], + $elements['numberOfIssues'], + 'PHPUnit warning', + ); + + $this->printList($elements['elements']); + } + + private function printTestsWithErrors(TestResult $result): void + { + if (!$result->hasTestErroredEvents()) { + return; + } + + $elements = []; + + foreach ($result->testErroredEvents() as $event) { + if ($event instanceof AfterLastTestMethodErrored || $event instanceof BeforeFirstTestMethodErrored) { + $title = $event->testClassName(); + } else { + $title = $this->name($event->test()); + } + + $elements[] = [ + 'title' => $title, + 'body' => $event->throwable()->asString(), + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'error'); + $this->printList($elements); + } + + private function printTestsWithFailedAssertions(TestResult $result): void + { + if (!$result->hasTestFailedEvents()) { + return; + } + + $elements = []; + + foreach ($result->testFailedEvents() as $event) { + $body = $event->throwable()->asString(); + + if (str_starts_with($body, 'AssertionError: ')) { + $body = substr($body, strlen('AssertionError: ')); + } + + $elements[] = [ + 'title' => $this->name($event->test()), + 'body' => $body, + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'failure'); + $this->printList($elements); + } + + private function printRiskyTests(TestResult $result): void + { + if (!$result->hasTestConsideredRiskyEvents()) { + return; + } + + $elements = $this->mapTestsWithIssuesEventsToElements($result->testConsideredRiskyEvents()); + + $this->printListHeaderWithNumber($elements['numberOfTestsWithIssues'], 'risky test'); + $this->printList($elements['elements']); + } + + private function printIncompleteTests(TestResult $result): void + { + if (!$result->hasTestMarkedIncompleteEvents()) { + return; + } + + $elements = []; + + foreach ($result->testMarkedIncompleteEvents() as $event) { + $elements[] = [ + 'title' => $this->name($event->test()), + 'body' => $event->throwable()->asString(), + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'incomplete test'); + $this->printList($elements); + } + + private function printSkippedTestSuites(TestResult $result): void + { + if (!$result->hasTestSuiteSkippedEvents()) { + return; + } + + $elements = []; + + foreach ($result->testSuiteSkippedEvents() as $event) { + $elements[] = [ + 'title' => $event->testSuite()->name(), + 'body' => $event->message(), + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'skipped test suite'); + $this->printList($elements); + } + + private function printSkippedTests(TestResult $result): void + { + if (!$result->hasTestSkippedEvents()) { + return; + } + + $elements = []; + + foreach ($result->testSkippedEvents() as $event) { + $elements[] = [ + 'title' => $this->name($event->test()), + 'body' => $event->message(), + ]; + } + + $this->printListHeaderWithNumber(count($elements), 'skipped test'); + $this->printList($elements); + } + + /** + * @param non-empty-string $type + * @param list $issues + */ + private function printIssueList(string $type, array $issues, bool $stackTrace = false): void + { + if ($issues === []) { + return; + } + + $numberOfUniqueIssues = count($issues); + $triggeringTests = []; + + foreach ($issues as $issue) { + $triggeringTests = array_merge($triggeringTests, array_keys($issue->triggeringTests())); + } + + $numberOfTests = count(array_unique($triggeringTests)); + unset($triggeringTests); + + $this->printListHeader( + sprintf( + '%d test%s triggered %d %s%s:' . PHP_EOL . PHP_EOL, + $numberOfTests, + $numberOfTests !== 1 ? 's' : '', + $numberOfUniqueIssues, + $type, + $numberOfUniqueIssues !== 1 ? 's' : '', + ), + ); + + $i = 1; + + foreach ($issues as $issue) { + $title = sprintf( + '%s:%d', + $issue->file(), + $issue->line(), + ); + + $body = trim($issue->description()) . PHP_EOL . PHP_EOL; + + if ($stackTrace && $issue->hasStackTrace()) { + $body .= trim($issue->stackTrace()) . PHP_EOL . PHP_EOL; + } + + if (!$issue->triggeredInTest()) { + $body .= 'Triggered by:'; + + $triggeringTests = $issue->triggeringTests(); + + ksort($triggeringTests); + + foreach ($triggeringTests as $triggeringTest) { + $body .= PHP_EOL . PHP_EOL . '* ' . $triggeringTest['test']->id(); + + if ($triggeringTest['count'] > 1) { + $body .= sprintf( + ' (%d times)', + $triggeringTest['count'], + ); + } + + if ($triggeringTest['test']->isTestMethod()) { + $body .= PHP_EOL . ' ' . $triggeringTest['test']->file() . ':' . $triggeringTest['test']->line(); + } + } + } + + $this->printIssueListElement($i++, $title, $body); + + $this->printer->print(PHP_EOL); + } + } + + private function printListHeaderWithNumberOfTestsAndNumberOfIssues(int $numberOfTestsWithIssues, int $numberOfIssues, string $type): void + { + $this->printListHeader( + sprintf( + "%d test%s triggered %d %s%s:\n\n", + $numberOfTestsWithIssues, + $numberOfTestsWithIssues !== 1 ? 's' : '', + $numberOfIssues, + $type, + $numberOfIssues !== 1 ? 's' : '', + ), + ); + } + + private function printListHeaderWithNumber(int $number, string $type): void + { + $this->printListHeader( + sprintf( + "There %s %d %s%s:\n\n", + ($number === 1) ? 'was' : 'were', + $number, + $type, + ($number === 1) ? '' : 's', + ), + ); + } + + private function printListHeader(string $header): void + { + if ($this->listPrinted) { + $this->printer->print("--\n\n"); + } + + $this->listPrinted = true; + + $this->printer->print($header); + } + + /** + * @param list $elements + */ + private function printList(array $elements): void + { + $i = 1; + + if ($this->displayDefectsInReverseOrder) { + $elements = array_reverse($elements); + } + + foreach ($elements as $element) { + $this->printListElement($i++, $element['title'], $element['body']); + } + + $this->printer->print("\n"); + } + + private function printListElement(int $number, string $title, string $body): void + { + $body = trim($body); + + $this->printer->print( + sprintf( + "%s%d) %s\n%s%s", + $number > 1 ? "\n" : '', + $number, + $title, + $body, + $body !== '' ? "\n" : '', + ), + ); + } + + private function printIssueListElement(int $number, string $title, string $body): void + { + $body = trim($body); + + $this->printer->print( + sprintf( + "%d) %s\n%s%s", + $number, + $title, + $body, + $body !== '' ? "\n" : '', + ), + ); + } + + private function name(Test $test): string + { + if ($test->isTestMethod()) { + assert($test instanceof TestMethod); + + if (!$test->testData()->hasDataFromDataProvider()) { + return $test->nameWithClass(); + } + + return $test->className() . '::' . $test->methodName() . $test->testData()->dataFromDataProvider()->dataAsStringForResultOutput(); + } + + return $test->name(); + } + + /** + * @param array> $events + * + * @return array{numberOfTestsWithIssues: int, numberOfIssues: int, elements: list} + */ + private function mapTestsWithIssuesEventsToElements(array $events): array + { + $elements = []; + $issues = 0; + + foreach ($events as $reasons) { + $test = $reasons[0]->test(); + $testLocation = $this->testLocation($test); + $title = $this->name($test); + $body = ''; + $first = true; + $single = count($reasons) === 1; + + foreach ($reasons as $reason) { + if ($first) { + $first = false; + } else { + $body .= PHP_EOL; + } + + $body .= $this->reasonMessage($reason, $single); + $body .= $this->reasonLocation($reason, $single); + + $issues++; + } + + if ($testLocation !== '') { + $body .= $testLocation; + } + + $elements[] = [ + 'title' => $title, + 'body' => $body, + ]; + } + + return [ + 'numberOfTestsWithIssues' => count($events), + 'numberOfIssues' => $issues, + 'elements' => $elements, + ]; + } + + private function testLocation(Test $test): string + { + if (!$test->isTestMethod()) { + return ''; + } + + assert($test instanceof TestMethod); + + return sprintf( + '%s%s:%d%s', + PHP_EOL, + $test->file(), + $test->line(), + PHP_EOL, + ); + } + + private function reasonMessage(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string + { + $message = trim($reason->message()); + + if ($single) { + return $message . PHP_EOL; + } + + $lines = explode(PHP_EOL, $message); + $buffer = '* ' . $lines[0] . PHP_EOL; + + if (count($lines) > 1) { + foreach (range(1, count($lines) - 1) as $line) { + $buffer .= ' ' . $lines[$line] . PHP_EOL; + } + } + + return $buffer; + } + + private function reasonLocation(ConsideredRisky|DeprecationTriggered|ErrorTriggered|NoticeTriggered|PhpDeprecationTriggered|PhpNoticeTriggered|PhpunitDeprecationTriggered|PhpunitErrorTriggered|PhpunitNoticeTriggered|PhpunitWarningTriggered|PhpWarningTriggered|WarningTriggered $reason, bool $single): string + { + if (!$reason instanceof DeprecationTriggered && + !$reason instanceof PhpDeprecationTriggered && + !$reason instanceof ErrorTriggered && + !$reason instanceof NoticeTriggered && + !$reason instanceof PhpNoticeTriggered && + !$reason instanceof WarningTriggered && + !$reason instanceof PhpWarningTriggered) { + return ''; + } + + return sprintf( + '%s%s:%d%s', + $single ? '' : ' ', + $reason->file(), + $reason->line(), + PHP_EOL, + ); + } +} diff --git a/src/TextUI/Output/Default/UnexpectedOutputPrinter.php b/src/TextUI/Output/Default/UnexpectedOutputPrinter.php new file mode 100644 index 00000000000..b51d51060fc --- /dev/null +++ b/src/TextUI/Output/Default/UnexpectedOutputPrinter.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use PHPUnit\Event\Facade; +use PHPUnit\Event\Test\PrintedUnexpectedOutput; +use PHPUnit\Event\Test\PrintedUnexpectedOutputSubscriber; +use PHPUnit\TextUI\Output\Printer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final readonly class UnexpectedOutputPrinter implements PrintedUnexpectedOutputSubscriber +{ + private Printer $printer; + + public function __construct(Printer $printer, Facade $facade) + { + $this->printer = $printer; + + $facade->registerSubscriber($this); + } + + public function notify(PrintedUnexpectedOutput $event): void + { + $this->printer->print($event->output()); + } +} diff --git a/src/TextUI/Output/Facade.php b/src/TextUI/Output/Facade.php new file mode 100644 index 00000000000..2a50017b0b7 --- /dev/null +++ b/src/TextUI/Output/Facade.php @@ -0,0 +1,275 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use const PHP_EOL; +use function assert; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Logging\TeamCity\TeamCityLogger; +use PHPUnit\Logging\TestDox\TestResultCollection; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\CannotOpenSocketException; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\InvalidSocketException; +use PHPUnit\TextUI\Output\Default\ProgressPrinter\ProgressPrinter as DefaultProgressPrinter; +use PHPUnit\TextUI\Output\Default\ResultPrinter as DefaultResultPrinter; +use PHPUnit\TextUI\Output\Default\UnexpectedOutputPrinter; +use PHPUnit\TextUI\Output\TestDox\ResultPrinter as TestDoxResultPrinter; +use SebastianBergmann\Timer\Duration; +use SebastianBergmann\Timer\ResourceUsageFormatter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Facade +{ + private static ?Printer $printer = null; + private static ?DefaultResultPrinter $defaultResultPrinter = null; + private static ?TestDoxResultPrinter $testDoxResultPrinter = null; + private static ?SummaryPrinter $summaryPrinter = null; + private static bool $defaultProgressPrinter = false; + + public static function init(Configuration $configuration, bool $extensionReplacesProgressOutput, bool $extensionReplacesResultOutput): Printer + { + self::createPrinter($configuration); + + assert(self::$printer !== null); + + if ($configuration->debug()) { + return self::$printer; + } + + self::createUnexpectedOutputPrinter(); + + if (!$extensionReplacesProgressOutput) { + self::createProgressPrinter($configuration); + } + + if (!$extensionReplacesResultOutput) { + self::createResultPrinter($configuration); + self::createSummaryPrinter($configuration); + } + + if ($configuration->outputIsTeamCity()) { + new TeamCityLogger( + DefaultPrinter::standardOutput(), + EventFacade::instance(), + ); + } + + return self::$printer; + } + + /** + * @param ?array $testDoxResult + */ + public static function printResult(TestResult $result, ?array $testDoxResult, Duration $duration, bool $stackTraceForDeprecations): void + { + assert(self::$printer !== null); + + if ($result->numberOfTestsRun() > 0) { + if (self::$defaultProgressPrinter) { + self::$printer->print(PHP_EOL . PHP_EOL); + } + + self::$printer->print((new ResourceUsageFormatter)->resourceUsage($duration) . PHP_EOL . PHP_EOL); + } + + if (self::$testDoxResultPrinter !== null && $testDoxResult !== null) { + self::$testDoxResultPrinter->print($result, $testDoxResult); + } + + if (self::$defaultResultPrinter !== null) { + self::$defaultResultPrinter->print($result, $stackTraceForDeprecations); + } + + if (self::$summaryPrinter !== null) { + self::$summaryPrinter->print($result); + } + } + + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function printerFor(string $target): Printer + { + if ($target === 'php://stdout') { + if (!self::$printer instanceof NullPrinter) { + return self::$printer; + } + + return DefaultPrinter::standardOutput(); + } + + return DefaultPrinter::from($target); + } + + private static function createPrinter(Configuration $configuration): void + { + $printerNeeded = false; + + if ($configuration->debug()) { + $printerNeeded = true; + } + + if ($configuration->outputIsTeamCity()) { + $printerNeeded = true; + } + + if ($configuration->outputIsTestDox()) { + $printerNeeded = true; + } + + if (!$configuration->noOutput() && !$configuration->noProgress()) { + $printerNeeded = true; + } + + if (!$configuration->noOutput() && !$configuration->noResults()) { + $printerNeeded = true; + } + + if ($printerNeeded) { + if ($configuration->outputToStandardErrorStream()) { + self::$printer = DefaultPrinter::standardError(); + + return; + } + + self::$printer = DefaultPrinter::standardOutput(); + + return; + } + + self::$printer = new NullPrinter; + } + + private static function createProgressPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + + if (!self::useDefaultProgressPrinter($configuration)) { + return; + } + + new DefaultProgressPrinter( + self::$printer, + EventFacade::instance(), + $configuration->colors(), + $configuration->columns(), + $configuration->source(), + ); + + self::$defaultProgressPrinter = true; + } + + private static function useDefaultProgressPrinter(Configuration $configuration): bool + { + if ($configuration->noOutput()) { + return false; + } + + if ($configuration->noProgress()) { + return false; + } + + if ($configuration->outputIsTeamCity()) { + return false; + } + + return true; + } + + private static function createResultPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + + if ($configuration->outputIsTestDox()) { + self::$defaultResultPrinter = new DefaultResultPrinter( + self::$printer, + $configuration->displayDetailsOnPhpunitDeprecations() || $configuration->displayDetailsOnAllIssues(), + true, + $configuration->displayDetailsOnPhpunitNotices() || $configuration->displayDetailsOnAllIssues(), + true, + false, + false, + true, + false, + false, + $configuration->displayDetailsOnTestsThatTriggerDeprecations() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerErrors() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerNotices() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerWarnings() || $configuration->displayDetailsOnAllIssues(), + $configuration->reverseDefectList(), + ); + } + + if ($configuration->outputIsTestDox()) { + self::$testDoxResultPrinter = new TestDoxResultPrinter( + self::$printer, + $configuration->colors(), + $configuration->columns(), + $configuration->testDoxOutputWithSummary(), + ); + } + + if ($configuration->noOutput() || $configuration->noResults()) { + return; + } + + if (self::$defaultResultPrinter !== null) { + return; + } + + self::$defaultResultPrinter = new DefaultResultPrinter( + self::$printer, + $configuration->displayDetailsOnPhpunitDeprecations() || $configuration->displayDetailsOnAllIssues(), + true, + $configuration->displayDetailsOnPhpunitNotices() || $configuration->displayDetailsOnAllIssues(), + true, + true, + true, + true, + $configuration->displayDetailsOnIncompleteTests() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnSkippedTests() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerDeprecations() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerErrors() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerNotices() || $configuration->displayDetailsOnAllIssues(), + $configuration->displayDetailsOnTestsThatTriggerWarnings() || $configuration->displayDetailsOnAllIssues(), + $configuration->reverseDefectList(), + ); + } + + private static function createSummaryPrinter(Configuration $configuration): void + { + assert(self::$printer !== null); + + if (($configuration->noOutput() || $configuration->noResults()) && + !($configuration->outputIsTeamCity() || $configuration->outputIsTestDox())) { + return; + } + + self::$summaryPrinter = new SummaryPrinter( + self::$printer, + $configuration->colors(), + ); + } + + private static function createUnexpectedOutputPrinter(): void + { + assert(self::$printer !== null); + + new UnexpectedOutputPrinter(self::$printer, EventFacade::instance()); + } +} diff --git a/src/TextUI/Output/Printer/DefaultPrinter.php b/src/TextUI/Output/Printer/DefaultPrinter.php new file mode 100644 index 00000000000..382f4815403 --- /dev/null +++ b/src/TextUI/Output/Printer/DefaultPrinter.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use function assert; +use function count; +use function dirname; +use function explode; +use function fclose; +use function fopen; +use function fsockopen; +use function fwrite; +use function str_replace; +use function str_starts_with; +use PHPUnit\Runner\DirectoryDoesNotExistException; +use PHPUnit\TextUI\CannotOpenSocketException; +use PHPUnit\TextUI\InvalidSocketException; +use PHPUnit\Util\Filesystem; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class DefaultPrinter implements Printer +{ + /** + * @var closed-resource|resource + */ + private $stream; + private readonly bool $isPhpStream; + private bool $isOpen; + + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function from(string $out): self + { + return new self($out); + } + + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function standardOutput(): self + { + return new self('php://stdout'); + } + + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + public static function standardError(): self + { + return new self('php://stderr'); + } + + /** + * @throws CannotOpenSocketException + * @throws DirectoryDoesNotExistException + * @throws InvalidSocketException + */ + private function __construct(string $out) + { + $this->isPhpStream = str_starts_with($out, 'php://'); + + if (str_starts_with($out, 'socket://')) { + $tmp = explode(':', str_replace('socket://', '', $out)); + + if (count($tmp) !== 2) { + throw new InvalidSocketException($out); + } + + $stream = @fsockopen($tmp[0], (int) $tmp[1]); + + if ($stream === false) { + throw new CannotOpenSocketException($tmp[0], (int) $tmp[1]); + } + + $this->stream = $stream; + $this->isOpen = true; + + return; + } + + if (!$this->isPhpStream && !Filesystem::createDirectory(dirname($out))) { + throw new DirectoryDoesNotExistException(dirname($out)); + } + + $stream = fopen($out, 'wb'); + + assert($stream !== false); + + $this->stream = $stream; + $this->isOpen = true; + } + + public function print(string $buffer): void + { + assert($this->isOpen); + + fwrite($this->stream, $buffer); + } + + public function flush(): void + { + if ($this->isOpen && $this->isPhpStream) { + fclose($this->stream); + + $this->isOpen = false; + } + } +} diff --git a/src/TextUI/Output/Printer/NullPrinter.php b/src/TextUI/Output/Printer/NullPrinter.php new file mode 100644 index 00000000000..5e6b7ddf225 --- /dev/null +++ b/src/TextUI/Output/Printer/NullPrinter.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class NullPrinter implements Printer +{ + public function print(string $buffer): void + { + } + + public function flush(): void + { + } +} diff --git a/src/TextUI/Output/Printer/Printer.php b/src/TextUI/Output/Printer/Printer.php new file mode 100644 index 00000000000..c9b0fb97069 --- /dev/null +++ b/src/TextUI/Output/Printer/Printer.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Printer +{ + public function print(string $buffer): void; + + public function flush(): void; +} diff --git a/src/TextUI/Output/SummaryPrinter.php b/src/TextUI/Output/SummaryPrinter.php new file mode 100644 index 00000000000..246fbf3ae1e --- /dev/null +++ b/src/TextUI/Output/SummaryPrinter.php @@ -0,0 +1,161 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output; + +use const PHP_EOL; +use function sprintf; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\Util\Color; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class SummaryPrinter +{ + private readonly Printer $printer; + private readonly bool $colors; + private bool $countPrinted = false; + + public function __construct(Printer $printer, bool $colors) + { + $this->printer = $printer; + $this->colors = $colors; + } + + public function print(TestResult $result): void + { + if ($result->numberOfTestsRun() === 0) { + $this->printWithColor( + 'fg-black, bg-yellow', + 'No tests executed!', + ); + + return; + } + + if ($result->wasSuccessful() && + !$result->hasIssues() && + !$result->hasTestSuiteSkippedEvents() && + !$result->hasTestSkippedEvents()) { + $this->printWithColor( + 'fg-black, bg-green', + sprintf( + 'OK (%d test%s, %d assertion%s)', + $result->numberOfTestsRun(), + $result->numberOfTestsRun() === 1 ? '' : 's', + $result->numberOfAssertions(), + $result->numberOfAssertions() === 1 ? '' : 's', + ), + ); + + $this->printNumberOfIssuesIgnoredByBaseline($result); + + return; + } + + if ($result->wasSuccessful()) { + if ($result->hasIssues()) { + $color = 'fg-black, bg-yellow'; + + $this->printWithColor( + $color, + 'OK, but there were issues!', + ); + } else { + $color = 'fg-black, bg-green'; + + $this->printWithColor( + $color, + 'OK, but some tests were skipped!', + ); + } + } else { + $color = 'fg-white, bg-red'; + + if ($result->hasTestErroredEvents() || $result->hasTestTriggeredPhpunitErrorEvents()) { + $this->printWithColor( + 'fg-white, bg-red', + 'ERRORS!', + ); + } else { + $this->printWithColor( + 'fg-white, bg-red', + 'FAILURES!', + ); + } + } + + $this->printCountString($result->numberOfTestsRun(), 'Tests', $color, true); + $this->printCountString($result->numberOfAssertions(), 'Assertions', $color, true); + $this->printCountString($result->numberOfErrors(), 'Errors', $color); + $this->printCountString($result->numberOfTestFailedEvents(), 'Failures', $color); + $this->printCountString($result->numberOfPhpunitWarnings(), 'PHPUnit Warnings', $color); + $this->printCountString($result->numberOfWarnings(), 'Warnings', $color); + $this->printCountString($result->numberOfPhpOrUserDeprecations(), 'Deprecations', $color); + $this->printCountString($result->numberOfPhpunitDeprecations(), 'PHPUnit Deprecations', $color); + $this->printCountString($result->numberOfPhpunitNotices(), 'PHPUnit Notices', $color); + $this->printCountString($result->numberOfNotices(), 'Notices', $color); + $this->printCountString($result->numberOfTestSuiteSkippedEvents() + $result->numberOfTestSkippedEvents(), 'Skipped', $color); + $this->printCountString($result->numberOfTestMarkedIncompleteEvents(), 'Incomplete', $color); + $this->printCountString($result->numberOfTestsWithTestConsideredRiskyEvents(), 'Risky', $color); + $this->printWithColor($color, '.'); + + $this->printNumberOfIssuesIgnoredByBaseline($result); + } + + private function printCountString(int $count, string $name, string $color, bool $always = false): void + { + if ($always || $count > 0) { + $this->printWithColor( + $color, + sprintf( + '%s%s: %d', + $this->countPrinted ? ', ' : '', + $name, + $count, + ), + false, + ); + + $this->countPrinted = true; + } + } + + private function printWithColor(string $color, string $buffer, bool $lf = true): void + { + if ($this->colors) { + $buffer = Color::colorizeTextBox($color, $buffer); + } + + $this->printer->print($buffer); + + if ($lf) { + $this->printer->print(PHP_EOL); + } + } + + private function printNumberOfIssuesIgnoredByBaseline(TestResult $result): void + { + if ($result->hasIssuesIgnoredByBaseline()) { + $this->printer->print( + sprintf( + '%s%d issue%s %s ignored by baseline.%s', + PHP_EOL, + $result->numberOfIssuesIgnoredByBaseline(), + $result->numberOfIssuesIgnoredByBaseline() > 1 ? 's' : '', + $result->numberOfIssuesIgnoredByBaseline() > 1 ? 'were' : 'was', + PHP_EOL, + ), + ); + } + } +} diff --git a/src/TextUI/Output/TestDox/ResultPrinter.php b/src/TextUI/Output/TestDox/ResultPrinter.php new file mode 100644 index 00000000000..27ae3cede9e --- /dev/null +++ b/src/TextUI/Output/TestDox/ResultPrinter.php @@ -0,0 +1,502 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\TestDox; + +use const PHP_EOL; +use function array_map; +use function explode; +use function implode; +use function preg_match; +use function preg_split; +use function rtrim; +use function sprintf; +use function str_starts_with; +use function trim; +use PHPUnit\Event\Code\Throwable; +use PHPUnit\Event\Test\AfterLastTestMethodErrored; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Framework\TestStatus\TestStatus; +use PHPUnit\Logging\TestDox\TestResult as TestDoxTestResult; +use PHPUnit\Logging\TestDox\TestResultCollection; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\Util\Color; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ResultPrinter +{ + private Printer $printer; + private bool $colors; + private int $columns; + private bool $printSummary; + + public function __construct(Printer $printer, bool $colors, int $columns, bool $printSummary) + { + $this->printer = $printer; + $this->colors = $colors; + $this->columns = $columns; + $this->printSummary = $printSummary; + } + + /** + * @param array $tests + */ + public function print(TestResult $result, array $tests): void + { + $this->doPrint($tests, false); + + if ($this->printSummary) { + $this->printer->print('Summary of tests with errors, failures, or issues:' . PHP_EOL . PHP_EOL); + + $this->doPrint($tests, true); + } + + $beforeFirstTestMethodErrored = []; + $afterLastTestMethodErrored = []; + + foreach ($result->testErroredEvents() as $error) { + if ($error instanceof BeforeFirstTestMethodErrored) { + $beforeFirstTestMethodErrored[$error->calledMethod()->className() . '::' . $error->calledMethod()->methodName()] = $error; + } + + if ($error instanceof AfterLastTestMethodErrored) { + $afterLastTestMethodErrored[$error->calledMethod()->className() . '::' . $error->calledMethod()->methodName()] = $error; + } + } + + $this->printBeforeClassOrAfterClassErrors( + 'before-first-test', + $beforeFirstTestMethodErrored, + ); + + $this->printBeforeClassOrAfterClassErrors( + 'after-last-test', + $afterLastTestMethodErrored, + ); + } + + /** + * @param array $tests + */ + private function doPrint(array $tests, bool $onlySummary): void + { + foreach ($tests as $prettifiedClassName => $_tests) { + $print = true; + + if ($onlySummary) { + $found = false; + + foreach ($_tests as $test) { + if ($test->status()->isSuccess()) { + continue; + } + + $found = true; + + break; + } + + if (!$found) { + $print = false; + } + } + + if (!$print) { + continue; + } + + $this->printPrettifiedClassName($prettifiedClassName); + + foreach ($_tests as $test) { + if ($onlySummary && $test->status()->isSuccess()) { + continue; + } + + $this->printTestResult($test); + } + + $this->printer->print(PHP_EOL); + } + } + + private function printPrettifiedClassName(string $prettifiedClassName): void + { + $buffer = $prettifiedClassName; + + if ($this->colors) { + $buffer = Color::colorizeTextBox('underlined', $buffer); + } + + $this->printer->print($buffer . PHP_EOL); + } + + private function printTestResult(TestDoxTestResult $test): void + { + $this->printTestResultHeader($test); + $this->printTestResultBody($test); + } + + private function printTestResultHeader(TestDoxTestResult $test): void + { + $buffer = ' ' . $this->symbolFor($test->status()) . ' '; + + if ($this->colors) { + $this->printer->print( + Color::colorizeTextBox( + $this->colorFor($test->status()), + $buffer, + ), + ); + } else { + $this->printer->print($buffer); + } + + $this->printer->print($test->test()->testDox()->prettifiedMethodName($this->colors) . PHP_EOL); + } + + private function printTestResultBody(TestDoxTestResult $test): void + { + if ($test->status()->isSuccess()) { + return; + } + + if (!$test->hasThrowable()) { + return; + } + + $this->printTestResultBodyStart($test); + $this->printThrowable($test->status(), $test->throwable()); + $this->printTestResultBodyEnd($test); + } + + private function printTestResultBodyStart(TestDoxTestResult $test): void + { + $this->printer->print( + $this->prefixLines( + $this->prefixFor('start', $test->status()), + '', + ), + ); + + $this->printer->print(PHP_EOL); + } + + private function printTestResultBodyEnd(TestDoxTestResult $test): void + { + $this->printer->print(PHP_EOL); + + $this->printer->print( + $this->prefixLines( + $this->prefixFor('last', $test->status()), + '', + ), + ); + + $this->printer->print(PHP_EOL); + } + + private function printThrowable(TestStatus $status, Throwable $throwable): void + { + $message = trim($throwable->description()); + $stackTrace = $this->formatStackTrace($throwable->stackTrace()); + $diff = ''; + + if ($message !== '' && $this->colors) { + ['message' => $message, 'diff' => $diff] = $this->colorizeMessageAndDiff( + $message, + $this->messageColorFor($status), + ); + } + + if ($message !== '') { + $this->printer->print( + $this->prefixLines( + $this->prefixFor('message', $status), + $message, + ), + ); + + $this->printer->print(PHP_EOL); + } + + if ($diff !== '') { + $this->printer->print( + $this->prefixLines( + $this->prefixFor('diff', $status), + $diff, + ), + ); + + $this->printer->print(PHP_EOL); + } + + if ($stackTrace !== '') { + if ($message !== '' || $diff !== '') { + $tracePrefix = $this->prefixFor('default', $status); + } else { + $tracePrefix = $this->prefixFor('trace', $status); + } + + $this->printer->print( + $this->prefixLines($tracePrefix, PHP_EOL . $stackTrace), + ); + } + + if ($throwable->hasPrevious()) { + $this->printer->print(PHP_EOL); + + $this->printer->print( + $this->prefixLines( + $this->prefixFor('default', $status), + ' ', + ), + ); + + $this->printer->print(PHP_EOL); + + $this->printer->print( + $this->prefixLines( + $this->prefixFor('default', $status), + 'Caused by:', + ), + ); + + $this->printer->print(PHP_EOL); + + $this->printThrowable($status, $throwable->previous()); + } + } + + /** + * @return array{message: string, diff: string} + */ + private function colorizeMessageAndDiff(string $buffer, string $style): array + { + $lines = []; + + if ($buffer !== '') { + $lines = array_map('\rtrim', explode(PHP_EOL, $buffer)); + } + + $message = []; + $diff = []; + $insideDiff = false; + + foreach ($lines as $line) { + if ($line === '--- Expected') { + $insideDiff = true; + } + + if (!$insideDiff) { + $message[] = $line; + } else { + if (str_starts_with($line, '-')) { + $line = Color::colorize('fg-red', Color::visualizeWhitespace($line, true)); + } elseif (str_starts_with($line, '+')) { + $line = Color::colorize('fg-green', Color::visualizeWhitespace($line, true)); + } elseif ($line === '@@ @@') { + $line = Color::colorize('fg-cyan', $line); + } + + $diff[] = $line; + } + } + + $message = implode(PHP_EOL, $message); + $diff = implode(PHP_EOL, $diff); + + if ($message !== '') { + // Testdox output has a left-margin of 5; keep right-margin to prevent terminal scrolling + $message = Color::colorizeTextBox($style, $message, $this->columns - 7); + } + + return [ + 'message' => $message, + 'diff' => $diff, + ]; + } + + private function formatStackTrace(string $stackTrace): string + { + if (!$this->colors) { + return rtrim($stackTrace); + } + + $lines = []; + $previousPath = ''; + + foreach (explode(PHP_EOL, $stackTrace) as $line) { + if (preg_match('/^(.*):(\d+)$/', $line, $matches) > 0) { + $lines[] = Color::colorizePath($matches[1], $previousPath) . Color::dim(':') . Color::colorize('fg-blue', $matches[2]) . "\n"; + $previousPath = $matches[1]; + + continue; + } + + $lines[] = $line; + $previousPath = ''; + } + + return rtrim(implode('', $lines)); + } + + private function prefixLines(string $prefix, string $message): string + { + $lines = preg_split('/\r\n|\r|\n/', $message); + + if ($lines === false) { + $lines = []; + } + + return implode( + PHP_EOL, + array_map( + static fn (string $line) => ' ' . $prefix . ($line !== '' ? ' ' . $line : ''), + $lines, + ), + ); + } + + /** + * @param 'default'|'diff'|'last'|'message'|'start'|'trace' $type + */ + private function prefixFor(string $type, TestStatus $status): string + { + if (!$this->colors) { + return '│'; + } + + return Color::colorize( + $this->colorFor($status), + match ($type) { + 'default' => '│', + 'start' => '┐', + 'message' => '├', + 'diff' => '┊', + 'trace' => '╵', + 'last' => '┴', + }, + ); + } + + private function colorFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return 'fg-green'; + } + + if ($status->isError()) { + return 'fg-yellow'; + } + + if ($status->isFailure()) { + return 'fg-red'; + } + + if ($status->isSkipped()) { + return 'fg-cyan'; + } + + if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return 'fg-yellow'; + } + + return 'fg-blue'; + } + + private function messageColorFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return ''; + } + + if ($status->isError()) { + return 'bg-yellow,fg-black'; + } + + if ($status->isFailure()) { + return 'bg-red,fg-white'; + } + + if ($status->isSkipped()) { + return 'fg-cyan'; + } + + if ($status->isIncomplete() || $status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return 'fg-yellow'; + } + + return 'fg-white,bg-blue'; + } + + private function symbolFor(TestStatus $status): string + { + if ($status->isSuccess()) { + return '✔'; + } + + if ($status->isError() || $status->isFailure()) { + return '✘'; + } + + if ($status->isSkipped()) { + return '↩'; + } + + if ($status->isDeprecation() || $status->isNotice() || $status->isRisky() || $status->isWarning()) { + return '⚠'; + } + + if ($status->isIncomplete()) { + return '∅'; + } + + return '?'; + } + + /** + * @param 'after-last-test'|'before-first-test' $type + * @param array $errors + */ + private function printBeforeClassOrAfterClassErrors(string $type, array $errors): void + { + if ($errors === []) { + return; + } + + $this->printer->print( + sprintf( + 'These %s methods errored:' . PHP_EOL . PHP_EOL, + $type, + ), + ); + + $index = 0; + + foreach ($errors as $method => $error) { + $this->printer->print( + sprintf( + '%d) %s' . PHP_EOL, + ++$index, + $method, + ), + ); + + $this->printer->print(trim($error->throwable()->description()) . PHP_EOL . PHP_EOL); + $this->printer->print($this->formatStackTrace($error->throwable()->stackTrace()) . PHP_EOL); + } + + $this->printer->print(PHP_EOL); + } +} diff --git a/src/TextUI/ShellExitCodeCalculator.php b/src/TextUI/ShellExitCodeCalculator.php new file mode 100644 index 00000000000..cc95d33c161 --- /dev/null +++ b/src/TextUI/ShellExitCodeCalculator.php @@ -0,0 +1,184 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Configuration\Configuration; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ShellExitCodeCalculator +{ + private const int SUCCESS_EXIT = 0; + private const int FAILURE_EXIT = 1; + private const int EXCEPTION_EXIT = 2; + + public function calculate(Configuration $configuration, TestResult $result): int + { + $failOnDeprecation = false; + $failOnPhpunitDeprecation = false; + $failOnPhpunitNotice = false; + $failOnPhpunitWarning = false; + $failOnEmptyTestSuite = false; + $failOnIncomplete = false; + $failOnNotice = false; + $failOnRisky = false; + $failOnSkipped = false; + $failOnWarning = false; + + if ($configuration->failOnAllIssues()) { + $failOnDeprecation = true; + $failOnPhpunitDeprecation = true; + $failOnPhpunitNotice = true; + $failOnPhpunitWarning = true; + $failOnEmptyTestSuite = true; + $failOnIncomplete = true; + $failOnNotice = true; + $failOnRisky = true; + $failOnSkipped = true; + $failOnWarning = true; + } + + if ($configuration->failOnDeprecation()) { + $failOnDeprecation = true; + } + + if ($configuration->doNotFailOnDeprecation()) { + $failOnDeprecation = false; + } + + if ($configuration->failOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = true; + } + + if ($configuration->doNotFailOnPhpunitDeprecation()) { + $failOnPhpunitDeprecation = false; + } + + if ($configuration->failOnPhpunitNotice()) { + $failOnPhpunitNotice = true; + } + + if ($configuration->doNotFailOnPhpunitNotice()) { + $failOnPhpunitNotice = false; + } + + if ($configuration->failOnPhpunitWarning()) { + $failOnPhpunitWarning = true; + } + + if ($configuration->doNotFailOnPhpunitWarning()) { + $failOnPhpunitWarning = false; + } + + if ($configuration->failOnEmptyTestSuite()) { + $failOnEmptyTestSuite = true; + } + + if ($configuration->doNotFailOnEmptyTestSuite()) { + $failOnEmptyTestSuite = false; + } + + if ($configuration->failOnIncomplete()) { + $failOnIncomplete = true; + } + + if ($configuration->doNotFailOnIncomplete()) { + $failOnIncomplete = false; + } + + if ($configuration->failOnNotice()) { + $failOnNotice = true; + } + + if ($configuration->doNotFailOnNotice()) { + $failOnNotice = false; + } + + if ($configuration->failOnRisky()) { + $failOnRisky = true; + } + + if ($configuration->doNotFailOnRisky()) { + $failOnRisky = false; + } + + if ($configuration->failOnSkipped()) { + $failOnSkipped = true; + } + + if ($configuration->doNotFailOnSkipped()) { + $failOnSkipped = false; + } + + if ($configuration->failOnWarning()) { + $failOnWarning = true; + } + + if ($configuration->doNotFailOnWarning()) { + $failOnWarning = false; + } + + $returnCode = self::FAILURE_EXIT; + + if ($result->wasSuccessful()) { + $returnCode = self::SUCCESS_EXIT; + } + + if ($failOnEmptyTestSuite && !$result->hasTests()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnDeprecation && $result->hasPhpOrUserDeprecations()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnPhpunitDeprecation && $result->hasPhpunitDeprecations()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnPhpunitNotice && $result->hasPhpunitNotices()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnPhpunitWarning && $result->hasPhpunitWarnings()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnIncomplete && $result->hasIncompleteTests()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnNotice && $result->hasNotices()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnRisky && $result->hasRiskyTests()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnSkipped && $result->hasSkippedTests()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($failOnWarning && $result->hasWarnings()) { + $returnCode = self::FAILURE_EXIT; + } + + if ($result->hasErrors()) { + $returnCode = self::EXCEPTION_EXIT; + } + + return $returnCode; + } +} diff --git a/src/TextUI/TestRunner.php b/src/TextUI/TestRunner.php new file mode 100644 index 00000000000..6e6107b5f2f --- /dev/null +++ b/src/TextUI/TestRunner.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function mt_srand; +use PHPUnit\Event; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\ResultCache\ResultCache; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\Configuration\Configuration; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class TestRunner +{ + /** + * @throws RuntimeException + */ + public function run(Configuration $configuration, ResultCache $resultCache, TestSuite $suite): void + { + try { + Event\Facade::emitter()->testRunnerStarted(); + + if ($configuration->executionOrder() === TestSuiteSorter::ORDER_RANDOMIZED) { + mt_srand($configuration->randomOrderSeed()); + } + + if ($configuration->executionOrder() !== TestSuiteSorter::ORDER_DEFAULT || + $configuration->executionOrderDefects() !== TestSuiteSorter::ORDER_DEFAULT || + $configuration->resolveDependencies()) { + $resultCache->load(); + + new TestSuiteSorter($resultCache)->reorderTestsInSuite( + $suite, + $configuration->executionOrder(), + $configuration->resolveDependencies(), + $configuration->executionOrderDefects(), + ); + + Event\Facade::emitter()->testSuiteSorted( + $configuration->executionOrder(), + $configuration->executionOrderDefects(), + $configuration->resolveDependencies(), + ); + } + + (new TestSuiteFilterProcessor)->process($configuration, $suite); + + Event\Facade::emitter()->testRunnerExecutionStarted( + Event\TestSuite\TestSuiteBuilder::from($suite), + ); + + $suite->run(); + + Event\Facade::emitter()->testRunnerExecutionFinished(); + Event\Facade::emitter()->testRunnerFinished(); + } catch (Throwable $t) { + throw new RuntimeException( + $t->getMessage(), + (int) $t->getCode(), + $t, + ); + } + } +} diff --git a/src/TextUI/TestSuiteFilterProcessor.php b/src/TextUI/TestSuiteFilterProcessor.php new file mode 100644 index 00000000000..c0e4beb1936 --- /dev/null +++ b/src/TextUI/TestSuiteFilterProcessor.php @@ -0,0 +1,101 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI; + +use function array_map; +use PHPUnit\Event; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Runner\Filter\Factory; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\FilterNotConfiguredException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class TestSuiteFilterProcessor +{ + /** + * @throws Event\RuntimeException + * @throws FilterNotConfiguredException + */ + public function process(Configuration $configuration, TestSuite $suite): void + { + $factory = new Factory; + + if (!$configuration->hasFilter() && + !$configuration->hasGroups() && + !$configuration->hasExcludeGroups() && + !$configuration->hasExcludeFilter() && + !$configuration->hasTestsCovering() && + !$configuration->hasTestsUsing() && + !$configuration->hasTestsRequiringPhpExtension()) { + return; + } + + if ($configuration->hasExcludeGroups()) { + $factory->addExcludeGroupFilter( + $configuration->excludeGroups(), + ); + } + + if ($configuration->hasGroups()) { + $factory->addIncludeGroupFilter( + $configuration->groups(), + ); + } + + if ($configuration->hasTestsCovering()) { + $factory->addIncludeGroupFilter( + array_map( + static fn (string $name): string => '__phpunit_covers_' . $name, + $configuration->testsCovering(), + ), + ); + } + + if ($configuration->hasTestsUsing()) { + $factory->addIncludeGroupFilter( + array_map( + static fn (string $name): string => '__phpunit_uses_' . $name, + $configuration->testsUsing(), + ), + ); + } + + if ($configuration->hasTestsRequiringPhpExtension()) { + $factory->addIncludeGroupFilter( + array_map( + static fn (string $name): string => '__phpunit_requires_php_extension' . $name, + $configuration->testsRequiringPhpExtension(), + ), + ); + } + + if ($configuration->hasExcludeFilter()) { + $factory->addExcludeNameFilter( + $configuration->excludeFilter(), + ); + } + + if ($configuration->hasFilter()) { + $factory->addIncludeNameFilter( + $configuration->filter(), + ); + } + + $suite->injectFilter($factory); + + Event\Facade::emitter()->testSuiteFiltered( + Event\TestSuite\TestSuiteBuilder::from($suite), + ); + } +} diff --git a/src/Util/Color.php b/src/Util/Color.php new file mode 100644 index 00000000000..c225e37b73e --- /dev/null +++ b/src/Util/Color.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function array_map; +use function array_walk; +use function count; +use function explode; +use function implode; +use function max; +use function min; +use function preg_replace; +use function preg_replace_callback; +use function preg_split; +use function sprintf; +use function str_pad; +use function strtr; +use function trim; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class Color +{ + /** + * @var non-empty-array + */ + private const array WHITESPACE_MAP = [ + ' ' => '·', + "\t" => '⇥', + ]; + + /** + * @var non-empty-array + */ + private const array WHITESPACE_EOL_MAP = [ + ' ' => '·', + "\t" => '⇥', + "\n" => '↵', + "\r" => '⟵', + ]; + + /** + * @var non-empty-array + */ + private const array ANSI_CODES = [ + 'reset' => '0', + 'bold' => '1', + 'dim' => '2', + 'dim-reset' => '22', + 'underlined' => '4', + 'fg-default' => '39', + 'fg-black' => '30', + 'fg-red' => '31', + 'fg-green' => '32', + 'fg-yellow' => '33', + 'fg-blue' => '34', + 'fg-magenta' => '35', + 'fg-cyan' => '36', + 'fg-white' => '37', + 'bg-default' => '49', + 'bg-black' => '40', + 'bg-red' => '41', + 'bg-green' => '42', + 'bg-yellow' => '43', + 'bg-blue' => '44', + 'bg-magenta' => '45', + 'bg-cyan' => '46', + 'bg-white' => '47', + ]; + + public static function colorize(string $color, string $buffer): string + { + if (trim($buffer) === '') { + return $buffer; + } + + $codes = array_map('\trim', explode(',', $color)); + $styles = []; + + foreach ($codes as $code) { + if (isset(self::ANSI_CODES[$code])) { + $styles[] = self::ANSI_CODES[$code]; + } + } + + if ($styles === []) { + return $buffer; + } + + return self::optimizeColor(sprintf("\x1b[%sm", implode(';', $styles)) . $buffer . "\x1b[0m"); + } + + public static function colorizeTextBox(string $color, string $buffer, ?int $columns = null): string + { + $lines = preg_split('/\r\n|\r|\n/', $buffer); + $maxBoxWidth = max(array_map('\strlen', $lines)); + + if ($columns !== null) { + $maxBoxWidth = min($maxBoxWidth, $columns); + } + + array_walk($lines, static function (string &$line) use ($color, $maxBoxWidth): void + { + $line = self::colorize($color, str_pad($line, $maxBoxWidth)); + }); + + return implode(PHP_EOL, $lines); + } + + public static function colorizePath(string $path, ?string $previousPath = null, bool $colorizeFilename = false): string + { + if ($previousPath === null) { + $previousPath = ''; + } + + $path = explode(DIRECTORY_SEPARATOR, $path); + $previousPath = explode(DIRECTORY_SEPARATOR, $previousPath); + + for ($i = 0; $i < min(count($path), count($previousPath)); $i++) { + if ($path[$i] === $previousPath[$i]) { + $path[$i] = self::dim($path[$i]); + } + } + + if ($colorizeFilename) { + $last = count($path) - 1; + $path[$last] = preg_replace_callback( + '/([\-_.]+|phpt$)/', + static fn (array $matches) => self::dim($matches[0]), + $path[$last], + ); + } + + return self::optimizeColor(implode(self::dim(DIRECTORY_SEPARATOR), $path)); + } + + public static function dim(string $buffer): string + { + if (trim($buffer) === '') { + return $buffer; + } + + return "\e[2m{$buffer}\e[22m"; + } + + public static function visualizeWhitespace(string $buffer, bool $visualizeEOL = false): string + { + $replaceMap = $visualizeEOL ? self::WHITESPACE_EOL_MAP : self::WHITESPACE_MAP; + + return preg_replace_callback( + '/\s+/', + static fn (array $matches) => self::dim(strtr($matches[0], $replaceMap)), + $buffer, + ); + } + + private static function optimizeColor(string $buffer): string + { + return preg_replace( + [ + "/\e\\[22m\e\\[2m/", + "/\e\\[([^m]*)m\e\\[([1-9][0-9;]*)m/", + "/(\e\\[[^m]*m)+(\e\\[0m)/", + ], + [ + '', + "\e[$1;$2m", + '$2', + ], + $buffer, + ); + } +} diff --git a/src/Util/Exception/Exception.php b/src/Util/Exception/Exception.php new file mode 100644 index 00000000000..58f42db77f3 --- /dev/null +++ b/src/Util/Exception/Exception.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This interface is not covered by the backward compatibility promise for PHPUnit + */ +interface Exception extends Throwable +{ +} diff --git a/src/Util/Exception/InvalidDirectoryException.php b/src/Util/Exception/InvalidDirectoryException.php new file mode 100644 index 00000000000..623af2ded5f --- /dev/null +++ b/src/Util/Exception/InvalidDirectoryException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidDirectoryException extends RuntimeException implements Exception +{ + public function __construct(string $directory) + { + parent::__construct( + sprintf( + '"%s" is not a directory', + $directory, + ), + ); + } +} diff --git a/src/Util/Exception/InvalidJsonException.php b/src/Util/Exception/InvalidJsonException.php new file mode 100644 index 00000000000..224f7115c59 --- /dev/null +++ b/src/Util/Exception/InvalidJsonException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidJsonException extends RuntimeException implements Exception +{ +} diff --git a/src/Util/Exception/InvalidVersionOperatorException.php b/src/Util/Exception/InvalidVersionOperatorException.php new file mode 100644 index 00000000000..bc2fe9a0ed5 --- /dev/null +++ b/src/Util/Exception/InvalidVersionOperatorException.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function sprintf; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class InvalidVersionOperatorException extends RuntimeException implements Exception +{ + public function __construct(string $operator) + { + parent::__construct( + sprintf( + '"%s" is not a valid version_compare() operator', + $operator, + ), + ); + } +} diff --git a/src/Util/Exception/PhpProcessException.php b/src/Util/Exception/PhpProcessException.php new file mode 100644 index 00000000000..05069ef05ec --- /dev/null +++ b/src/Util/Exception/PhpProcessException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Util\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class PhpProcessException extends RuntimeException implements Exception +{ +} diff --git a/src/Util/Exception/XmlException.php b/src/Util/Exception/XmlException.php new file mode 100644 index 00000000000..127e1ecaffe --- /dev/null +++ b/src/Util/Exception/XmlException.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Xml; + +use PHPUnit\Util\Exception; +use RuntimeException; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class XmlException extends RuntimeException implements Exception +{ +} diff --git a/src/Util/ExcludeList.php b/src/Util/ExcludeList.php new file mode 100644 index 00000000000..1e3edd4e42d --- /dev/null +++ b/src/Util/ExcludeList.php @@ -0,0 +1,230 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const PHP_OS_FAMILY; +use function array_any; +use function assert; +use function class_exists; +use function defined; +use function dirname; +use function is_dir; +use function realpath; +use function str_starts_with; +use function sys_get_temp_dir; +use Composer\Autoload\ClassLoader; +use DeepCopy\DeepCopy; +use PharIo\Manifest\Manifest; +use PharIo\Version\Version as PharIoVersion; +use PhpParser\Parser; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use SebastianBergmann\CliParser\Parser as CliParser; +use SebastianBergmann\CodeCoverage\CodeCoverage; +use SebastianBergmann\Comparator\Comparator; +use SebastianBergmann\Complexity\Calculator; +use SebastianBergmann\Diff\Diff; +use SebastianBergmann\Environment\Runtime; +use SebastianBergmann\Exporter\Exporter; +use SebastianBergmann\FileIterator\Facade as FileIteratorFacade; +use SebastianBergmann\GlobalState\Snapshot; +use SebastianBergmann\Invoker\Invoker; +use SebastianBergmann\LinesOfCode\Counter; +use SebastianBergmann\ObjectEnumerator\Enumerator; +use SebastianBergmann\ObjectReflector\ObjectReflector; +use SebastianBergmann\RecursionContext\Context; +use SebastianBergmann\Template\Template; +use SebastianBergmann\Timer\Timer; +use SebastianBergmann\Type\TypeName; +use SebastianBergmann\Version; +use staabm\SideEffectsDetector\SideEffectsDetector; +use TheSeer\Tokenizer\Tokenizer; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class ExcludeList +{ + /** + * @var non-empty-array + */ + private const array EXCLUDED_CLASS_NAMES = [ + // composer + ClassLoader::class => 1, + + // myclabs/deepcopy + DeepCopy::class => 1, + + // nikic/php-parser + Parser::class => 1, + + // phar-io/manifest + Manifest::class => 1, + + // phar-io/version + PharIoVersion::class => 1, + + // phpunit/phpunit + TestCase::class => 2, + + // phpunit/php-code-coverage + CodeCoverage::class => 1, + + // phpunit/php-file-iterator + FileIteratorFacade::class => 1, + + // phpunit/php-invoker + Invoker::class => 1, + + // phpunit/php-text-template + Template::class => 1, + + // phpunit/php-timer + Timer::class => 1, + + // sebastian/cli-parser + CliParser::class => 1, + + // sebastian/comparator + Comparator::class => 1, + + // sebastian/complexity + Calculator::class => 1, + + // sebastian/diff + Diff::class => 1, + + // sebastian/environment + Runtime::class => 1, + + // sebastian/exporter + Exporter::class => 1, + + // sebastian/global-state + Snapshot::class => 1, + + // sebastian/lines-of-code + Counter::class => 1, + + // sebastian/object-enumerator + Enumerator::class => 1, + + // sebastian/object-reflector + ObjectReflector::class => 1, + + // sebastian/recursion-context + Context::class => 1, + + // sebastian/type + TypeName::class => 1, + + // sebastian/version + Version::class => 1, + + // staabm/side-effects-detector + SideEffectsDetector::class => 1, + + // theseer/tokenizer + Tokenizer::class => 1, + ]; + + /** + * @var list + */ + private static array $directories = []; + private static bool $initialized = false; + private readonly bool $enabled; + + /** + * @param non-empty-string $directory + * + * @throws InvalidDirectoryException + */ + public static function addDirectory(string $directory): void + { + if (!is_dir($directory)) { + throw new InvalidDirectoryException($directory); + } + + $directory = realpath($directory); + + assert($directory !== false); + + self::$directories[] = $directory; + } + + public function __construct(?bool $enabled = null) + { + if ($enabled === null) { + $enabled = !defined('PHPUNIT_TESTSUITE'); + } + + $this->enabled = $enabled; + } + + /** + * @return list + */ + public function getExcludedDirectories(): array + { + self::initialize(); + + return self::$directories; + } + + public function isExcluded(string $file): bool + { + if (!$this->enabled) { + return false; + } + + self::initialize(); + + return array_any( + self::$directories, + static fn (string $directory) => str_starts_with($file, $directory), + ); + } + + private static function initialize(): void + { + if (self::$initialized) { + return; + } + + foreach (self::EXCLUDED_CLASS_NAMES as $className => $parent) { + if (!class_exists($className)) { + continue; + } + + $directory = new ReflectionClass($className)->getFileName(); + + for ($i = 0; $i < $parent; $i++) { + $directory = dirname($directory); + } + + self::$directories[] = $directory; + } + + /** + * Hide process isolation workaround on Windows: + * tempnam() prefix is limited to first 3 characters. + * + * @see https://php.net/manual/en/function.tempnam.php + */ + if (PHP_OS_FAMILY === 'Windows') { + // @codeCoverageIgnoreStart + self::$directories[] = sys_get_temp_dir() . '\\PHP'; + // @codeCoverageIgnoreEnd + } + + self::$initialized = true; + } +} diff --git a/src/Util/Exporter.php b/src/Util/Exporter.php new file mode 100644 index 00000000000..182499e9da0 --- /dev/null +++ b/src/Util/Exporter.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\TextUI\Configuration\Registry as ConfigurationRegistry; +use SebastianBergmann\Exporter\Exporter as OriginalExporter; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + */ +final class Exporter +{ + private static ?OriginalExporter $exporter = null; + + public static function export(mixed $value): string + { + return self::exporter()->export($value); + } + + /** + * @param array $data + */ + public static function shortenedRecursiveExport(array $data): string + { + return self::exporter()->shortenedRecursiveExport($data); + } + + public static function shortenedExport(mixed $value): string + { + return self::exporter()->shortenedExport($value); + } + + private static function exporter(): OriginalExporter + { + if (self::$exporter !== null) { + return self::$exporter; + } + + self::$exporter = new OriginalExporter( + ConfigurationRegistry::get()->shortenArraysForExportThreshold(), + ); + + return self::$exporter; + } +} diff --git a/src/Util/Filesystem.php b/src/Util/Filesystem.php new file mode 100644 index 00000000000..3da54042379 --- /dev/null +++ b/src/Util/Filesystem.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use function basename; +use function dirname; +use function is_dir; +use function mkdir; +use function realpath; +use function str_starts_with; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filesystem +{ + public static function createDirectory(string $directory): bool + { + return !(!is_dir($directory) && !@mkdir($directory, 0o777, true) && !is_dir($directory)); + } + + /** + * @param non-empty-string $path + * + * @return false|non-empty-string + */ + public static function resolveStreamOrFile(string $path): false|string + { + if (str_starts_with($path, 'php://') || str_starts_with($path, 'socket://')) { + return $path; + } + + $directory = dirname($path); + + if (is_dir($directory)) { + return realpath($directory) . DIRECTORY_SEPARATOR . basename($path); + } + + return false; + } +} diff --git a/src/Util/Filter.php b/src/Util/Filter.php new file mode 100644 index 00000000000..1abb0063651 --- /dev/null +++ b/src/Util/Filter.php @@ -0,0 +1,133 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function array_any; +use function array_unshift; +use function defined; +use function in_array; +use function is_array; +use function is_file; +use function realpath; +use function sprintf; +use function str_starts_with; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\PhptAssertionFailedError; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Filter +{ + /** + * @throws Exception + */ + public static function stackTraceFromThrowableAsString(Throwable $t, bool $unwrap = true): string + { + if ($t instanceof PhptAssertionFailedError) { + $stackTrace = $t->syntheticTrace(); + $file = $t->syntheticFile(); + $line = $t->syntheticLine(); + } elseif ($t instanceof Exception) { + $stackTrace = $t->getSerializableTrace(); + $file = $t->getFile(); + $line = $t->getLine(); + } else { + if ($unwrap && $t->getPrevious() !== null) { + $t = $t->getPrevious(); + } + + $stackTrace = $t->getTrace(); + $file = $t->getFile(); + $line = $t->getLine(); + } + + if (!self::frameExists($stackTrace, $file, $line)) { + array_unshift( + $stackTrace, + ['file' => $file, 'line' => $line], + ); + } + + return self::stackTraceAsString($stackTrace); + } + + /** + * @param list $frames + */ + private static function stackTraceAsString(array $frames): string + { + $buffer = ''; + $prefix = defined('__PHPUNIT_PHAR_ROOT__') ? __PHPUNIT_PHAR_ROOT__ : false; + $excludeList = new ExcludeList; + + foreach ($frames as $frame) { + if (self::shouldPrintFrame($frame, $prefix, $excludeList)) { + $buffer .= sprintf( + "%s:%s\n", + $frame['file'], + $frame['line'] ?? '?', + ); + } + } + + return $buffer; + } + + /** + * @param array{file?: non-empty-string} $frame + */ + private static function shouldPrintFrame(array $frame, false|string $prefix, ExcludeList $excludeList): bool + { + if (!isset($frame['file'])) { + return false; + } + + $file = $frame['file']; + $fileIsNotPrefixed = $prefix === false || !str_starts_with($file, $prefix); + + // @see https://github.com/sebastianbergmann/phpunit/issues/4033 + if (isset($GLOBALS['_SERVER']['SCRIPT_NAME'])) { + $script = realpath($GLOBALS['_SERVER']['SCRIPT_NAME']); + } else { + // @codeCoverageIgnoreStart + $script = ''; + // @codeCoverageIgnoreEnd + } + + return $fileIsNotPrefixed && + $file !== $script && + self::fileIsExcluded($file, $excludeList) && + is_file($file); + } + + private static function fileIsExcluded(string $file, ExcludeList $excludeList): bool + { + return (!isset($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) || + !is_array($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) || + $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] === [] || + !in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], true)) && + !$excludeList->isExcluded($file); + } + + /** + * @param list $trace + */ + private static function frameExists(array $trace, string $file, int $line): bool + { + return array_any( + $trace, + static fn (array $frame) => isset($frame['file'], $frame['line']) && $frame['file'] === $file && $frame['line'] === $line, + ); + } +} diff --git a/src/Util/GlobalState.php b/src/Util/GlobalState.php new file mode 100644 index 00000000000..067752a3c92 --- /dev/null +++ b/src/Util/GlobalState.php @@ -0,0 +1,338 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; +use function array_reverse; +use function array_shift; +use function assert; +use function defined; +use function get_defined_constants; +use function get_included_files; +use function in_array; +use function ini_get_all; +use function is_array; +use function is_file; +use function is_scalar; +use function preg_match; +use function serialize; +use function sprintf; +use function str_ends_with; +use function str_starts_with; +use function strtr; +use function var_export; +use Closure; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class GlobalState +{ + /** + * @var non-empty-list + */ + private const array SUPER_GLOBAL_ARRAYS = [ + '_ENV', + '_POST', + '_GET', + '_COOKIE', + '_SERVER', + '_FILES', + '_REQUEST', + ]; + + /** + * @var non-empty-array> + */ + private const array DEPRECATED_INI_SETTINGS = [ + '7.3' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'string.strip_tags' => true, + ], + + '7.4' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.func_overload' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'pdo_odbc.db2_instance_name' => true, + 'string.strip_tags' => true, + ], + + '8.0' => [ + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + ], + + '8.1' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.2' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.3' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.4' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.5' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + + '8.6' => [ + 'auto_detect_line_endings' => true, + 'filter.default' => true, + 'iconv.input_encoding' => true, + 'iconv.output_encoding' => true, + 'iconv.internal_encoding' => true, + 'mbstring.http_input' => true, + 'mbstring.http_output' => true, + 'mbstring.internal_encoding' => true, + 'oci8.old_oci_close_semantics' => true, + ], + ]; + + /** + * @throws Exception + */ + public static function getIncludedFilesAsString(): string + { + return self::processIncludedFilesAsString(get_included_files()); + } + + /** + * @param list $files + * + * @throws Exception + */ + public static function processIncludedFilesAsString(array $files): string + { + $excludeList = new ExcludeList; + $prefix = false; + $result = ''; + + if (defined('__PHPUNIT_PHAR__')) { + // @codeCoverageIgnoreStart + $prefix = 'phar://' . __PHPUNIT_PHAR__ . '/'; + // @codeCoverageIgnoreEnd + } + + // Do not process bootstrap script + array_shift($files); + + // If bootstrap script was a Composer bin proxy, skip the second entry as well + if (str_ends_with(strtr($files[0], '\\', '/'), '/phpunit/phpunit/phpunit')) { + // @codeCoverageIgnoreStart + array_shift($files); + // @codeCoverageIgnoreEnd + } + + foreach (array_reverse($files) as $file) { + if (isset($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) && + is_array($GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST']) && + $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'] !== [] && + in_array($file, $GLOBALS['__PHPUNIT_ISOLATION_EXCLUDE_LIST'], true)) { + continue; + } + + if ($prefix !== false && str_starts_with($file, $prefix)) { + continue; + } + + // Skip virtual file system protocols + if (preg_match('/^(vfs|phpvfs[a-z0-9]+):/', $file) > 0) { + continue; + } + + if (!$excludeList->isExcluded($file) && is_file($file)) { + $result = 'require_once \'' . $file . "';\n" . $result; + } + } + + return $result; + } + + public static function getIniSettingsAsString(): string + { + $result = ''; + + $iniSettings = ini_get_all(null, false); + + assert($iniSettings !== false); + + foreach ($iniSettings as $key => $value) { + if (self::isIniSettingDeprecated($key)) { + continue; + } + + $result .= sprintf( + '@ini_set(%s, %s);' . "\n", + self::exportVariable($key), + self::exportVariable((string) $value), + ); + } + + return $result; + } + + public static function getConstantsAsString(): string + { + $constants = get_defined_constants(true); + $result = ''; + + if (isset($constants['user'])) { + foreach ($constants['user'] as $name => $value) { + $result .= sprintf( + 'if (!defined(\'%s\')) define(\'%s\', %s);' . "\n", + $name, + $name, + self::exportVariable($value), + ); + } + } + + return $result; + } + + public static function getGlobalsAsString(): string + { + $result = ''; + + foreach (self::SUPER_GLOBAL_ARRAYS as $superGlobalArray) { + if (isset($GLOBALS[$superGlobalArray]) && is_array($GLOBALS[$superGlobalArray])) { + foreach ($GLOBALS[$superGlobalArray] as $key => $value) { + if ($value instanceof Closure) { + continue; + } + + $result .= sprintf( + '$GLOBALS[\'%s\'][\'%s\'] = %s;' . "\n", + $superGlobalArray, + $key, + self::exportVariable($GLOBALS[$superGlobalArray][$key]), + ); + } + } + } + + $excludeList = self::SUPER_GLOBAL_ARRAYS; + $excludeList[] = 'GLOBALS'; + + foreach ($GLOBALS as $key => $value) { + if (!$value instanceof Closure && !in_array($key, $excludeList, true)) { + $result .= sprintf( + '$GLOBALS[\'%s\'] = %s;' . "\n", + $key, + self::exportVariable($value), + ); + } + } + + return $result; + } + + private static function exportVariable(mixed $variable): string + { + if (is_scalar($variable) || $variable === null || + (is_array($variable) && self::arrayOnlyContainsScalars($variable))) { + return var_export($variable, true); + } + + return 'unserialize(' . var_export(serialize($variable), true) . ')'; + } + + /** + * @param array $array + */ + private static function arrayOnlyContainsScalars(array $array): bool + { + $result = true; + + foreach ($array as $element) { + if (is_array($element)) { + $result = self::arrayOnlyContainsScalars($element); + } elseif (!is_scalar($element) && $element !== null) { + $result = false; + } + + if (!$result) { + break; + } + } + + return $result; + } + + private static function isIniSettingDeprecated(string $iniSetting): bool + { + return isset(self::DEPRECATED_INI_SETTINGS[PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION][$iniSetting]); + } +} diff --git a/src/Util/Http/Downloader.php b/src/Util/Http/Downloader.php new file mode 100644 index 00000000000..a9af2e38fbb --- /dev/null +++ b/src/Util/Http/Downloader.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Http; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +interface Downloader +{ + /** + * @param non-empty-string $url + */ + public function download(string $url): false|string; +} diff --git a/src/Util/Http/PhpDownloader.php b/src/Util/Http/PhpDownloader.php new file mode 100644 index 00000000000..5969c042609 --- /dev/null +++ b/src/Util/Http/PhpDownloader.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Http; + +use function file_get_contents; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + * + * @codeCoverageIgnore + */ +final class PhpDownloader implements Downloader +{ + /** + * @param non-empty-string $url + */ + public function download(string $url): false|string + { + return file_get_contents($url); + } +} diff --git a/src/Util/Json.php b/src/Util/Json.php new file mode 100644 index 00000000000..cbe959accd1 --- /dev/null +++ b/src/Util/Json.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const JSON_ERROR_NONE; +use const JSON_PRETTY_PRINT; +use const JSON_UNESCAPED_SLASHES; +use const JSON_UNESCAPED_UNICODE; +use const SORT_STRING; +use function assert; +use function is_object; +use function is_scalar; +use function json_decode; +use function json_encode; +use function json_last_error; +use function ksort; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Json +{ + /** + * @throws InvalidJsonException + */ + public static function prettify(string $json): string + { + $decodedJson = json_decode($json, false); + + if (json_last_error() !== JSON_ERROR_NONE) { + throw new InvalidJsonException; + } + + $result = json_encode($decodedJson, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE); + + assert($result !== false); + + return $result; + } + + /** + * Element 0 is true and element 1 is null when JSON decoding did not work. + * * Element 0 is false and element 1 has the decoded value when JSON decoding did work. + * * This is used to avoid ambiguity with JSON strings consisting entirely of 'null' or 'false'. + * + * @return array{0: false, 1: mixed}|array{0: true, 1: null} + */ + public static function canonicalize(string $json): array + { + $decodedJson = json_decode($json); + + if (json_last_error() !== JSON_ERROR_NONE) { + return [true, null]; + } + + self::recursiveSort($decodedJson); + + $reencodedJson = json_encode($decodedJson); + + return [false, $reencodedJson]; + } + + /** + * JSON object keys are unordered while PHP array keys are ordered. + * + * Sort all array keys to ensure both the expected and actual values have + * their keys in the same order. + */ + private static function recursiveSort(mixed &$json): void + { + if ($json === null || $json === [] || is_scalar($json)) { + return; + } + + $isObject = is_object($json); + + if ($isObject) { + // Objects need to be sorted during canonicalization to ensure + // correct comparsion since JSON objects are unordered. It must be + // kept as an object so that the value correctly stays as a JSON + // object instead of potentially being converted to an array. This + // approach ensures that numeric string JSON keys are preserved and + // don't risk being flattened due to PHP's array semantics. + // See #2919, #4584, #4674 + $json = (array) $json; + ksort($json, SORT_STRING); + } + + foreach ($json as &$value) { + self::recursiveSort($value); + } + + if ($isObject) { + $json = (object) $json; + } + } +} diff --git a/src/Util/PHP/DefaultJobRunner.php b/src/Util/PHP/DefaultJobRunner.php new file mode 100644 index 00000000000..07319c7baac --- /dev/null +++ b/src/Util/PHP/DefaultJobRunner.php @@ -0,0 +1,263 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use const PHP_BINARY; +use const PHP_SAPI; +use function array_keys; +use function array_merge; +use function array_values; +use function assert; +use function fclose; +use function file_put_contents; +use function function_exists; +use function fwrite; +use function ini_get_all; +use function is_array; +use function is_resource; +use function proc_close; +use function proc_open; +use function str_starts_with; +use function stream_get_contents; +use function sys_get_temp_dir; +use function tempnam; +use function trim; +use function unlink; +use function xdebug_is_debugger_active; +use PHPUnit\Event\Facade; +use PHPUnit\Runner\CodeCoverage; +use SebastianBergmann\Environment\Runtime; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class DefaultJobRunner extends JobRunner +{ + /** + * @throws PhpProcessException + */ + public function run(Job $job): Result + { + $temporaryFile = null; + + if ($job->hasInput()) { + $temporaryFile = tempnam(sys_get_temp_dir(), 'phpunit_'); + + if ($temporaryFile === false || + file_put_contents($temporaryFile, $job->code()) === false) { + // @codeCoverageIgnoreStart + throw new PhpProcessException( + 'Unable to write temporary file', + ); + // @codeCoverageIgnoreEnd + } + + $job = new Job( + $job->input(), + $job->phpSettings(), + $job->environmentVariables(), + $job->arguments(), + null, + $job->redirectErrors(), + $job->requiresXdebug(), + ); + } + + assert($temporaryFile !== ''); + + return $this->runProcess($job, $temporaryFile); + } + + /** + * @param ?non-empty-string $temporaryFile + * + * @throws PhpProcessException + */ + private function runProcess(Job $job, ?string $temporaryFile): Result + { + $environmentVariables = null; + + if ($job->hasEnvironmentVariables()) { + /** @phpstan-ignore nullCoalesce.variable */ + $environmentVariables = $_SERVER ?? []; + + unset($environmentVariables['argv'], $environmentVariables['argc']); + + $environmentVariables = array_merge($environmentVariables, $job->environmentVariables()); + + foreach ($environmentVariables as $key => $value) { + if (is_array($value)) { + unset($environmentVariables[$key]); + } + } + + unset($key, $value); + } + + $pipeSpec = [ + 0 => ['pipe', 'r'], + 1 => ['pipe', 'w'], + 2 => ['pipe', 'w'], + ]; + + if ($job->redirectErrors()) { + $pipeSpec[2] = ['redirect', 1]; + } + + $process = proc_open( + $this->buildCommand($job, $temporaryFile), + $pipeSpec, + $pipes, + null, + $environmentVariables, + ); + + if (!is_resource($process)) { + // @codeCoverageIgnoreStart + throw new PhpProcessException( + 'Unable to spawn worker process', + ); + // @codeCoverageIgnoreEnd + } + + Facade::emitter()->childProcessStarted(); + + fwrite($pipes[0], $job->code()); + fclose($pipes[0]); + + $stdout = ''; + $stderr = ''; + + if (isset($pipes[1])) { + $stdout = stream_get_contents($pipes[1]); + + fclose($pipes[1]); + } + + if (isset($pipes[2])) { + $stderr = stream_get_contents($pipes[2]); + + fclose($pipes[2]); + } + + proc_close($process); + + if ($temporaryFile !== null) { + unlink($temporaryFile); + } + + assert($stdout !== false); + assert($stderr !== false); + + return new Result($stdout, $stderr); + } + + /** + * @return non-empty-list + */ + private function buildCommand(Job $job, ?string $file): array + { + $runtime = new Runtime; + $command = [PHP_BINARY]; + $phpSettings = $job->phpSettings(); + + $xdebugModeConfiguredExplicitly = false; + + foreach ($phpSettings as $phpSetting) { + if (str_starts_with($phpSetting, 'xdebug.mode')) { + $xdebugModeConfiguredExplicitly = true; + + break; + } + } + + if ($runtime->hasPCOV()) { + $pcovSettings = ini_get_all('pcov'); + + assert($pcovSettings !== false); + + $phpSettings = array_merge( + $phpSettings, + $runtime->getCurrentSettings( + array_keys($pcovSettings), + ), + ); + } elseif ($runtime->hasXdebug()) { + assert(function_exists('xdebug_is_debugger_active')); + + $xdebugSettings = ini_get_all('xdebug'); + + assert($xdebugSettings !== false); + + $phpSettings = array_merge( + $phpSettings, + $runtime->getCurrentSettings( + array_keys($xdebugSettings), + ), + ); + + if ( + !$xdebugModeConfiguredExplicitly && + !CodeCoverage::instance()->isActive() && + xdebug_is_debugger_active() === false && + !$job->requiresXdebug() + ) { + // disable xdebug to speedup test execution + $phpSettings['xdebug.mode'] = 'xdebug.mode=off'; + } + } + + $command = array_merge($command, $this->settingsToParameters(array_values($phpSettings))); + + if (PHP_SAPI === 'phpdbg') { + $command[] = '-qrr'; + + if ($file === null) { + $command[] = 's='; + } + } + + if ($file !== null) { + $command[] = '-f'; + $command[] = $file; + } + + if ($job->hasArguments()) { + if ($file === null) { + $command[] = '--'; + } + + foreach ($job->arguments() as $argument) { + $command[] = trim($argument); + } + } + + return $command; + } + + /** + * @param list $settings + * + * @return list + */ + private function settingsToParameters(array $settings): array + { + $buffer = []; + + foreach ($settings as $setting) { + $buffer[] = '-d'; + $buffer[] = $setting; + } + + return $buffer; + } +} diff --git a/src/Util/PHP/Job.php b/src/Util/PHP/Job.php new file mode 100644 index 00000000000..172d3f59356 --- /dev/null +++ b/src/Util/PHP/Job.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Job +{ + /** + * @var non-empty-string + */ + private string $code; + + /** + * @var list + */ + private array $phpSettings; + + /** + * @var array + */ + private array $environmentVariables; + + /** + * @var list + */ + private array $arguments; + + /** + * @var ?non-empty-string + */ + private ?string $input; + private bool $redirectErrors; + private bool $requiresXdebug; + + /** + * @param non-empty-string $code + * @param list $phpSettings + * @param array $environmentVariables + * @param list $arguments + * @param ?non-empty-string $input + */ + public function __construct(string $code, array $phpSettings = [], array $environmentVariables = [], array $arguments = [], ?string $input = null, bool $redirectErrors = false, bool $requiresXdebug = false) + { + $this->code = $code; + $this->phpSettings = $phpSettings; + $this->environmentVariables = $environmentVariables; + $this->arguments = $arguments; + $this->input = $input; + $this->redirectErrors = $redirectErrors; + $this->requiresXdebug = $requiresXdebug; + } + + /** + * @return non-empty-string + */ + public function code(): string + { + return $this->code; + } + + /** + * @return list + */ + public function phpSettings(): array + { + return $this->phpSettings; + } + + /** + * @phpstan-assert-if-true !empty $this->environmentVariables + */ + public function hasEnvironmentVariables(): bool + { + return $this->environmentVariables !== []; + } + + /** + * @return array + */ + public function environmentVariables(): array + { + return $this->environmentVariables; + } + + /** + * @phpstan-assert-if-true !empty $this->arguments + */ + public function hasArguments(): bool + { + return $this->arguments !== []; + } + + /** + * @return list + */ + public function arguments(): array + { + return $this->arguments; + } + + /** + * @phpstan-assert-if-true !empty $this->input + */ + public function hasInput(): bool + { + return $this->input !== null; + } + + /** + * @throws PhpProcessException + * + * @return non-empty-string + */ + public function input(): string + { + if ($this->input === null) { + throw new PhpProcessException('No input specified'); + } + + return $this->input; + } + + public function redirectErrors(): bool + { + return $this->redirectErrors; + } + + public function requiresXdebug(): bool + { + return $this->requiresXdebug; + } +} diff --git a/src/Util/PHP/JobRunner.php b/src/Util/PHP/JobRunner.php new file mode 100644 index 00000000000..6805a0c44df --- /dev/null +++ b/src/Util/PHP/JobRunner.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use function assert; +use function file_get_contents; +use function is_file; +use function unlink; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\ChildProcessResultProcessor; +use PHPUnit\Framework\Test; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +abstract readonly class JobRunner +{ + private ChildProcessResultProcessor $processor; + + public function __construct(ChildProcessResultProcessor $processor) + { + $this->processor = $processor; + } + + /** + * @param non-empty-string $processResultFile + */ + final public function runTestJob(Job $job, string $processResultFile, Test $test): void + { + $result = $this->run($job); + + $processResult = ''; + + if (is_file($processResultFile)) { + $processResult = file_get_contents($processResultFile); + + assert($processResult !== false); + + @unlink($processResultFile); + } + + $this->processor->process( + $test, + $processResult, + $result->stderr(), + ); + + EventFacade::emitter()->childProcessFinished($result->stdout(), $result->stderr()); + } + + abstract public function run(Job $job): Result; +} diff --git a/src/Util/PHP/JobRunnerRegistry.php b/src/Util/PHP/JobRunnerRegistry.php new file mode 100644 index 00000000000..94e22a4e454 --- /dev/null +++ b/src/Util/PHP/JobRunnerRegistry.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Event\Facade; +use PHPUnit\Framework\ChildProcessResultProcessor; +use PHPUnit\Framework\Test; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestRunner\TestResult\PassedTests; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final class JobRunnerRegistry +{ + private static ?JobRunner $runner = null; + + public static function run(Job $job): Result + { + return self::runner()->run($job); + } + + /** + * @param non-empty-string $processResultFile + */ + public static function runTestJob(Job $job, string $processResultFile, Test $test): void + { + self::runner()->runTestJob($job, $processResultFile, $test); + } + + public static function set(JobRunner $runner): void + { + self::$runner = $runner; + } + + private static function runner(): JobRunner + { + if (self::$runner === null) { + self::$runner = new DefaultJobRunner( + new ChildProcessResultProcessor( + Facade::instance(), + Facade::emitter(), + PassedTests::instance(), + CodeCoverage::instance(), + ), + ); + } + + return self::$runner; + } +} diff --git a/src/Util/PHP/Result.php b/src/Util/PHP/Result.php new file mode 100644 index 00000000000..ed05822601b --- /dev/null +++ b/src/Util/PHP/Result.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +/** + * @immutable + * + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Result +{ + private string $stdout; + private string $stderr; + + public function __construct(string $stdout, string $stderr) + { + $this->stdout = $stdout; + $this->stderr = $stderr; + } + + public function stdout(): string + { + return $this->stdout; + } + + public function stderr(): string + { + return $this->stderr; + } +} diff --git a/src/Util/Reflection.php b/src/Util/Reflection.php new file mode 100644 index 00000000000..b61c19b9b46 --- /dev/null +++ b/src/Util/Reflection.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function array_keys; +use function array_merge; +use function array_reverse; +use function assert; +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use ReflectionException; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Reflection +{ + /** + * @param class-string $className + * @param non-empty-string $methodName + * + * @return array{file: non-empty-string, line: non-negative-int} + */ + public static function sourceLocationFor(string $className, string $methodName): array + { + try { + $reflector = new ReflectionMethod($className, $methodName); + + $file = $reflector->getFileName(); + $line = $reflector->getStartLine(); + } catch (ReflectionException) { + $file = 'unknown'; + $line = 0; + } + + assert($file !== false && $file !== ''); + assert($line !== false && $line >= 0); + + return [ + 'file' => $file, + 'line' => $line, + ]; + } + + /** + * @param ReflectionClass $class + * + * @return list + */ + public static function publicMethodsDeclaredDirectlyInTestClass(ReflectionClass $class): array + { + return self::filterAndSortMethods($class, ReflectionMethod::IS_PUBLIC, true); + } + + /** + * @param ReflectionClass $class + * + * @return list + */ + public static function methodsDeclaredDirectlyInTestClass(ReflectionClass $class): array + { + return self::filterAndSortMethods($class, null, false); + } + + /** + * @param ReflectionClass $class + * + * @return list + */ + private static function filterAndSortMethods(ReflectionClass $class, ?int $filter, bool $sortHighestToLowest): array + { + $methodsByClass = []; + + foreach ($class->getMethods($filter) as $method) { + $declaringClassName = $method->getDeclaringClass()->getName(); + + if ($declaringClassName === TestCase::class) { + continue; + } + + if ($declaringClassName === Assert::class) { + continue; + } + + if (!isset($methodsByClass[$declaringClassName])) { + $methodsByClass[$declaringClassName] = []; + } + + $methodsByClass[$declaringClassName][] = $method; + } + + $classNames = array_keys($methodsByClass); + + if ($sortHighestToLowest) { + $classNames = array_reverse($classNames); + } + + $methods = []; + + foreach ($classNames as $className) { + $methods = array_merge($methods, $methodsByClass[$className]); + } + + return $methods; + } +} diff --git a/src/Util/Test.php b/src/Util/Test.php new file mode 100644 index 00000000000..bcc2f371bbc --- /dev/null +++ b/src/Util/Test.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DEBUG_BACKTRACE_IGNORE_ARGS; +use const DEBUG_BACKTRACE_PROVIDE_OBJECT; +use function debug_backtrace; +use function str_starts_with; +use PHPUnit\Event\Code\NoTestCaseObjectOnCallStackException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Parser\Registry; +use ReflectionMethod; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Test +{ + /** + * @throws NoTestCaseObjectOnCallStackException + */ + public static function currentTestCase(): TestCase + { + foreach (debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) { + if (isset($frame['object']) && $frame['object'] instanceof TestCase) { + return $frame['object']; + } + } + + throw new NoTestCaseObjectOnCallStackException; + } + + public static function isTestMethod(ReflectionMethod $method): bool + { + if (!$method->isPublic()) { + return false; + } + + if (str_starts_with($method->getName(), 'test')) { + return true; + } + + $metadata = Registry::parser()->forMethod( + $method->getDeclaringClass()->getName(), + $method->getName(), + ); + + return $metadata->isTest()->isNotEmpty(); + } +} diff --git a/src/Util/ThrowableToStringMapper.php b/src/Util/ThrowableToStringMapper.php new file mode 100644 index 00000000000..0fcf3695b83 --- /dev/null +++ b/src/Util/ThrowableToStringMapper.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function trim; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\PhptAssertionFailedError; +use PHPUnit\Framework\SelfDescribing; +use PHPUnit\Runner\ErrorException; +use Throwable; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class ThrowableToStringMapper +{ + public static function map(Throwable $t): string + { + if ($t instanceof ErrorException) { + return $t->getMessage(); + } + + if ($t instanceof SelfDescribing) { + $buffer = $t->toString(); + + if ($t instanceof ExpectationFailedException && $t->getComparisonFailure() !== null) { + $buffer .= $t->getComparisonFailure()->getDiff(); + } + + if ($t instanceof PhptAssertionFailedError) { + $buffer .= $t->diff(); + } + + if ($buffer !== '') { + $buffer = trim($buffer) . "\n"; + } + + return $buffer; + } + + return $t::class . ': ' . $t->getMessage() . "\n"; + } +} diff --git a/src/Util/VersionComparisonOperator.php b/src/Util/VersionComparisonOperator.php new file mode 100644 index 00000000000..9dcba3c32a3 --- /dev/null +++ b/src/Util/VersionComparisonOperator.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function in_array; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @immutable + */ +final readonly class VersionComparisonOperator +{ + /** + * @var '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + private string $operator; + + /** + * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator + * + * @throws InvalidVersionOperatorException + */ + public function __construct(string $operator) + { + $this->ensureOperatorIsValid($operator); + + $this->operator = $operator; + } + + /** + * @return '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' + */ + public function asString(): string + { + return $this->operator; + } + + /** + * @param '!='|'<'|'<='|'<>'|'='|'=='|'>'|'>='|'eq'|'ge'|'gt'|'le'|'lt'|'ne' $operator + * + * @throws InvalidVersionOperatorException + */ + private function ensureOperatorIsValid(string $operator): void + { + if (!in_array($operator, ['<', 'lt', '<=', 'le', '>', 'gt', '>=', 'ge', '==', '=', 'eq', '!=', '<>', 'ne'], true)) { + throw new InvalidVersionOperatorException($operator); + } + } +} diff --git a/src/Util/Xml/Loader.php b/src/Util/Xml/Loader.php new file mode 100644 index 00000000000..03c3c20d24e --- /dev/null +++ b/src/Util/Xml/Loader.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Xml; + +use function error_reporting; +use function file_get_contents; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use function sprintf; +use function trim; +use DOMDocument; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Loader +{ + /** + * @throws XmlException + */ + public function loadFile(string $filename): DOMDocument + { + $reporting = error_reporting(0); + $contents = file_get_contents($filename); + + error_reporting($reporting); + + if ($contents === false) { + throw new XmlException( + sprintf( + 'Could not read XML from file "%s"', + $filename, + ), + ); + } + + if (trim($contents) === '') { + throw new XmlException( + sprintf( + 'Could not parse XML from empty file "%s"', + $filename, + ), + ); + } + + return $this->load($contents); + } + + /** + * @throws XmlException + */ + public function load(string $actual): DOMDocument + { + if ($actual === '') { + throw new XmlException('Could not parse XML from empty string'); + } + + $document = new DOMDocument; + $document->preserveWhiteSpace = false; + + $internal = libxml_use_internal_errors(true); + $message = ''; + $reporting = error_reporting(0); + $loaded = $document->loadXML($actual); + + foreach (libxml_get_errors() as $error) { + $message .= "\n" . $error->message; + } + + libxml_use_internal_errors($internal); + error_reporting($reporting); + + if ($loaded === false) { + if ($message === '') { + // @codeCoverageIgnoreStart + $message = 'Could not load XML for unknown reason'; + // @codeCoverageIgnoreEnd + } + + throw new XmlException($message); + } + + return $document; + } +} diff --git a/src/Util/Xml/Xml.php b/src/Util/Xml/Xml.php new file mode 100644 index 00000000000..5e30bb43b70 --- /dev/null +++ b/src/Util/Xml/Xml.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const ENT_QUOTES; +use function htmlspecialchars; +use function mb_convert_encoding; +use function ord; +use function preg_replace; +use function strlen; + +/** + * @no-named-arguments Parameter names are not covered by the backward compatibility promise for PHPUnit + * + * @internal This class is not covered by the backward compatibility promise for PHPUnit + */ +final readonly class Xml +{ + /** + * Escapes a string for the use in XML documents. + * + * Any Unicode character is allowed, excluding the surrogate blocks, FFFE, + * and FFFF (not even as character reference). + * + * @see https://www.w3.org/TR/xml/#charsets + */ + public static function prepareString(string $string): string + { + return preg_replace( + '/[\\x00-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]/', + '', + htmlspecialchars( + self::convertToUtf8($string), + ENT_QUOTES, + ), + ); + } + + private static function convertToUtf8(string $string): string + { + if (!self::isUtf8($string)) { + $string = mb_convert_encoding($string, 'UTF-8'); + } + + return $string; + } + + private static function isUtf8(string $string): bool + { + $length = strlen($string); + + for ($i = 0; $i < $length; $i++) { + if (ord($string[$i]) < 0x80) { + $n = 0; + } elseif ((ord($string[$i]) & 0xE0) === 0xC0) { + $n = 1; + } elseif ((ord($string[$i]) & 0xF0) === 0xE0) { + $n = 2; + } elseif ((ord($string[$i]) & 0xF0) === 0xF0) { + $n = 3; + } else { + return false; + } + + for ($j = 0; $j < $n; $j++) { + if ((++$i === $length) || ((ord($string[$i]) & 0xC0) !== 0x80)) { + return false; + } + } + } + + return true; + } +} diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000000..1f2f51c6c78 --- /dev/null +++ b/tests/README.md @@ -0,0 +1,17 @@ +# PHPUnit's Own Test Suite + +## Test Suite Structure + +This is the top-level directory structure of the `tests` directory: + +* `tests/unit` holds tests that are "regular" PHPUnit tests (implemented using `PHPUnit\Framework\TestCase`) +* `tests/end-to-end` holds tests in the [PHPT](https://qa.php.net/phpt_details.php) format +* `tests/end-to-end/phar` holds PHAR-specific tests that are not part of the regular `end-to-end` tests +* `tests/_files` holds test fixture that is used by tests in `tests/unit` and/or `tests/end-to-end` + +## Running the Test Suite + +* `./phpunit` will run all tests from `tests/unit` and `tests/end-to-end` (except the PHAR-specific tests) +* `./phpunit --testsuite unit` will run all tests from `tests/unit` +* `./phpunit --testsuite end-to-end` will run all tests from `tests/end-to-end` (except the PHAR-specific tests) +* `ant phar-snapshot run-phar-specific-tests` will build a PHAR and run the PHAR-specific tests diff --git a/tests/_files/3194.php b/tests/_files/3194.php new file mode 100644 index 00000000000..5240a977503 --- /dev/null +++ b/tests/_files/3194.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +trait T3194 +{ + public function doSomethingElse(): bool + { + return true; + } +} + +final class C3194 +{ + use T3194; + + public function doSomething(): bool + { + return $this->doSomethingElse(); + } +} + +#[CoversClass(C3194::class)] +final class Test3194 extends TestCase +{ + public function testOne(): void + { + $o = new C; + + $this->assertTrue($o->doSomething()); + } +} diff --git a/tests/_files/AbstractTrait.php b/tests/_files/AbstractTrait.php new file mode 100644 index 00000000000..b064c0ed95d --- /dev/null +++ b/tests/_files/AbstractTrait.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +trait AbstractTrait +{ + abstract public function doSomething(); + + public function mockableMethod() + { + return true; + } + + public function anotherMockableMethod() + { + return true; + } +} diff --git a/tests/_files/AbstractVariousIterableDataProviderTest.php b/tests/_files/AbstractVariousIterableDataProviderTest.php new file mode 100644 index 00000000000..7dad830f6fe --- /dev/null +++ b/tests/_files/AbstractVariousIterableDataProviderTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; + +abstract class AbstractVariousIterableDataProviderTest +{ + public static function asArrayProviderInParent() + { + return [ + ['J'], + ['K'], + ['L'], + ]; + } + + public static function asIteratorProviderInParent() + { + yield ['M']; + + yield ['N']; + + yield ['O']; + } + + public static function asTraversableProviderInParent() + { + return new WrapperIteratorAggregate([ + ['P'], + ['Q'], + ['R'], + ]); + } + + abstract public static function asArrayProvider(); + + abstract public static function asIteratorProvider(); + + abstract public static function asTraversableProvider(); + + #[DataProvider('asArrayProvider')] + #[DataProvider('asIteratorProvider')] + #[DataProvider('asTraversableProvider')] + public function testAbstract(string $x): void + { + } + + #[DataProvider('asArrayProviderInParent')] + #[DataProvider('asIteratorProviderInParent')] + #[DataProvider('asTraversableProviderInParent')] + public function testInParent(string $x): void + { + } +} diff --git a/tests/_files/ActualOutputTest.php b/tests/_files/ActualOutputTest.php new file mode 100644 index 00000000000..e01f4ab019e --- /dev/null +++ b/tests/_files/ActualOutputTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class ActualOutputTest extends TestCase +{ + public function testOne(): void + { + print '*'; + + $this->assertSame('*', $this->getActualOutputForAssertion()); + } +} diff --git a/tests/_files/AlternativeSuffixTest.test.php b/tests/_files/AlternativeSuffixTest.test.php new file mode 100644 index 00000000000..6abb44ce1c6 --- /dev/null +++ b/tests/_files/AlternativeSuffixTest.test.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class AlternativeSuffixTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } + + public function testThree(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/AnotherDummySubscriber.php b/tests/_files/AnotherDummySubscriber.php new file mode 100644 index 00000000000..a3010f45763 --- /dev/null +++ b/tests/_files/AnotherDummySubscriber.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Event\Subscriber; + +interface AnotherDummySubscriber extends Subscriber +{ + public function notify(DummyEvent $event): void; +} diff --git a/tests/_files/AssertionExample.php b/tests/_files/AssertionExample.php new file mode 100644 index 00000000000..c9c322a39d8 --- /dev/null +++ b/tests/_files/AssertionExample.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function assert; + +final class AssertionExample +{ + public function doSomething(): void + { + assert(false); + } +} diff --git a/tests/_files/AssertionExampleTest.php b/tests/_files/AssertionExampleTest.php new file mode 100644 index 00000000000..625ab79ab4f --- /dev/null +++ b/tests/_files/AssertionExampleTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class AssertionExampleTest extends TestCase +{ + public function testOne(): void + { + $e = new AssertionExample; + + $e->doSomething(); + } +} diff --git a/tests/_files/Author.php b/tests/_files/Author.php new file mode 100644 index 00000000000..f2403b1aa9d --- /dev/null +++ b/tests/_files/Author.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class Author +{ + // the order of properties is important for testing the cycle! + public $books = []; + private $name = ''; + + public function __construct($name) + { + $this->name = $name; + } +} diff --git a/tests/_files/BackedEnumeration.php b/tests/_files/BackedEnumeration.php new file mode 100644 index 00000000000..b9356b99512 --- /dev/null +++ b/tests/_files/BackedEnumeration.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +enum BackedEnumeration: string +{ + case Test = 'test'; +} diff --git a/tests/_files/BankAccount.php b/tests/_files/BankAccount.php new file mode 100644 index 00000000000..7921321e6b4 --- /dev/null +++ b/tests/_files/BankAccount.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class BankAccount +{ + /** + * The bank account's balance. + * + * @var float + */ + private $balance = 0; + + /** + * Returns the bank account's balance. + * + * @return float + */ + public function getBalance() + { + return $this->balance; + } + + /** + * Deposits an amount of money to the bank account. + * + * @param float $balance + * + * @throws BankAccountException + */ + public function depositMoney($balance) + { + $this->setBalance($this->getBalance() + $balance); + + return $this->getBalance(); + } + + /** + * Withdraws an amount of money from the bank account. + * + * @param float $balance + * + * @throws BankAccountException + */ + public function withdrawMoney($balance) + { + $this->setBalance($this->getBalance() - $balance); + + return $this->getBalance(); + } + + /** + * Sets the bank account's balance. + * + * @param float $balance + * + * @throws BankAccountException + */ + private function setBalance($balance): void + { + if ($balance >= 0) { + $this->balance = $balance; + } else { + throw new BankAccountException; + } + } +} diff --git a/tests/_files/BankAccountException.php b/tests/_files/BankAccountException.php new file mode 100644 index 00000000000..316c61a2510 --- /dev/null +++ b/tests/_files/BankAccountException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use RuntimeException; + +final class BankAccountException extends RuntimeException +{ +} diff --git a/tests/_files/BankAccountTest.php b/tests/_files/BankAccountTest.php new file mode 100644 index 00000000000..aec77f7961f --- /dev/null +++ b/tests/_files/BankAccountTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +#[CoversFunction(BankAccount::class)] +final class BankAccountTest extends TestCase +{ + #[Group('balanceIsInitiallyZero')] + #[Group('specification')] + #[Group('1234')] + public function testBalanceIsInitiallyZero(): void + { + /* @Given a fresh bank account */ + $ba = new BankAccount; + + /* @When I ask it for its balance */ + $balance = $ba->getBalance(); + + /* @Then I should get 0 */ + $this->assertEquals(0, $balance); + } + + #[Group('balanceCannotBecomeNegative')] + #[Group('specification')] + public function testBalanceCannotBecomeNegative(): void + { + $ba = new BankAccount; + + try { + $ba->withdrawMoney(1); + } catch (BankAccountException) { + $this->assertEquals(0, $ba->getBalance()); + + return; + } + + $this->fail(); + } + + #[Group('balanceCannotBecomeNegative')] + #[Group('specification')] + public function testBalanceCannotBecomeNegative2(): void + { + $ba = new BankAccount; + + try { + $ba->depositMoney(-1); + } catch (BankAccountException) { + $this->assertEquals(0, $ba->getBalance()); + + return; + } + + $this->fail(); + } +} diff --git a/tests/_files/Book.php b/tests/_files/Book.php new file mode 100644 index 00000000000..57d8a382ded --- /dev/null +++ b/tests/_files/Book.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class Book +{ + // the order of properties is important for testing the cycle! + public $author; +} diff --git a/tests/_files/ClassWithNonPublicAttributes.php b/tests/_files/ClassWithNonPublicAttributes.php new file mode 100644 index 00000000000..eeb36548e12 --- /dev/null +++ b/tests/_files/ClassWithNonPublicAttributes.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class ClassWithNonPublicAttributes extends ParentClassWithProtectedAttributes +{ + public static $publicStaticAttribute = 'foo'; + protected static $protectedStaticAttribute = 'bar'; + protected static $privateStaticAttribute = 'baz'; + public $publicAttribute = 'foo'; + public $foo = 1; + public $bar = 2; + public $publicArray = ['foo']; + protected $protectedAttribute = 'bar'; + protected $privateAttribute = 'baz'; + protected $protectedArray = ['bar']; + protected $privateArray = ['baz']; +} diff --git a/tests/_files/ClassWithScalarTypeDeclarations.php b/tests/_files/ClassWithScalarTypeDeclarations.php new file mode 100644 index 00000000000..d334cb5d6fc --- /dev/null +++ b/tests/_files/ClassWithScalarTypeDeclarations.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class ClassWithScalarTypeDeclarations +{ + public function foo(string $string, int $int): void + { + } +} diff --git a/tests/_files/ClassWithToString.php b/tests/_files/ClassWithToString.php new file mode 100644 index 00000000000..4195b190583 --- /dev/null +++ b/tests/_files/ClassWithToString.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Stringable; + +final class ClassWithToString implements Stringable +{ + public function __toString(): string + { + return 'string representation'; + } +} diff --git a/tests/_files/ComparisonFailureTest.php b/tests/_files/ComparisonFailureTest.php new file mode 100644 index 00000000000..02542f3b7a9 --- /dev/null +++ b/tests/_files/ComparisonFailureTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class ComparisonFailureTest extends TestCase +{ + public function testOne(): void + { + $this->assertEquals(true, false); + } +} diff --git a/tests/_files/ConcreteTest.my.php b/tests/_files/ConcreteTest.my.php new file mode 100644 index 00000000000..87c0b7e4de1 --- /dev/null +++ b/tests/_files/ConcreteTest.my.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class ConcreteTest extends AbstractTest +{ + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/ConcreteTest.php b/tests/_files/ConcreteTest.php new file mode 100644 index 00000000000..fa939c2af25 --- /dev/null +++ b/tests/_files/ConcreteTest.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\TestFixture\AbstractTest; + +final class ConcreteTest extends AbstractTest +{ + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/CoverageFunctionTest.php b/tests/_files/CoverageFunctionTest.php new file mode 100644 index 00000000000..05ad044baa2 --- /dev/null +++ b/tests/_files/CoverageFunctionTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\TestCase; + +#[CoversFunction('globalFunction')] +#[UsesFunction('globalFunction')] +final class CoverageFunctionTest extends TestCase +{ + public function testSomething(): void + { + globalFunction(); + } +} diff --git a/tests/_files/CoverageMethodTest.php b/tests/_files/CoverageMethodTest.php new file mode 100644 index 00000000000..52c0d169776 --- /dev/null +++ b/tests/_files/CoverageMethodTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\UsesMethod; +use PHPUnit\Framework\TestCase; + +#[CoversMethod(CoveredClass::class, 'publicMethod')] +#[UsesMethod(CoveredClass::class, 'publicMethod')] +final class CoverageMethodTest extends TestCase +{ + public function testSomething(): void + { + $o = new CoveredClass; + + $o->publicMethod(); + } +} diff --git a/tests/_files/CoverageNoneTest.php b/tests/_files/CoverageNoneTest.php new file mode 100644 index 00000000000..bbebec59a86 --- /dev/null +++ b/tests/_files/CoverageNoneTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class CoverageNoneTest extends TestCase +{ + public function testSomething(): void + { + $o = new CoveredClass; + + $o->publicMethod(); + } +} diff --git a/tests/_files/CoverageTraitTest.php b/tests/_files/CoverageTraitTest.php new file mode 100644 index 00000000000..37e26a38135 --- /dev/null +++ b/tests/_files/CoverageTraitTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\TestCase; + +#[CoversTrait(CoveredTrait::class)] +#[UsesTrait(CoveredTrait::class)] +final class CoverageTraitTest extends TestCase +{ + public function testSomething(): void + { + } +} diff --git a/tests/_files/CoveredClass.php b/tests/_files/CoveredClass.php new file mode 100644 index 00000000000..331a28e401a --- /dev/null +++ b/tests/_files/CoveredClass.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class CoveredClass extends CoveredParentClass +{ + public function publicMethod(): void + { + parent::publicMethod(); + $this->protectedMethod(); + } + + protected function protectedMethod(): void + { + parent::protectedMethod(); + $this->privateMethod(); + } + + private function privateMethod(): void + { + } +} diff --git a/tests/_files/CoveredClassUsingCoveredTrait.php b/tests/_files/CoveredClassUsingCoveredTrait.php new file mode 100644 index 00000000000..151f5b47d2e --- /dev/null +++ b/tests/_files/CoveredClassUsingCoveredTrait.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class CoveredClassUsingCoveredTrait +{ + use CoveredTrait; + + public function publicMethod(): void + { + } + + protected function protectedMethod(): void + { + } + + private function privateMethod(): void + { + } +} diff --git a/tests/_files/CoveredClassUsingCoveredTraitTest.php b/tests/_files/CoveredClassUsingCoveredTraitTest.php new file mode 100644 index 00000000000..2ea583bfc75 --- /dev/null +++ b/tests/_files/CoveredClassUsingCoveredTraitTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CoveredClassUsingCoveredTrait::class)] +#[UsesClass(CoveredClassUsingCoveredTrait::class)] +final class CoveredClassUsingCoveredTraitTest extends TestCase +{ + public function testSomething(): void + { + } +} diff --git a/tests/_files/CoveredFunction.php b/tests/_files/CoveredFunction.php new file mode 100644 index 00000000000..5fcce0f68d2 --- /dev/null +++ b/tests/_files/CoveredFunction.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +function globalFunction(): void +{ +} diff --git a/tests/_files/CoveredParentClass.php b/tests/_files/CoveredParentClass.php new file mode 100644 index 00000000000..fce85ca2903 --- /dev/null +++ b/tests/_files/CoveredParentClass.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +class CoveredParentClass +{ + public function publicMethod(): void + { + $this->protectedMethod(); + } + + protected function protectedMethod(): void + { + $this->privateMethod(); + } + + private function privateMethod(): void + { + } +} diff --git a/tests/_files/CoveredTrait.php b/tests/_files/CoveredTrait.php new file mode 100644 index 00000000000..9b9a37d454c --- /dev/null +++ b/tests/_files/CoveredTrait.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +trait CoveredTrait +{ + public function m(int $x, int $y): int + { + return $x + $y; + } +} diff --git a/tests/_files/CoversClassOnClassTest.php b/tests/_files/CoversClassOnClassTest.php new file mode 100644 index 00000000000..62d63175d9f --- /dev/null +++ b/tests/_files/CoversClassOnClassTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CoveredClass::class)] +#[UsesClass(CoveredClass::class)] +final class CoversClassOnClassTest extends TestCase +{ + public function testSomething(): void + { + $o = new CoveredClass; + + $o->publicMethod(); + } +} diff --git a/tests/_files/CoversNothingOnClassTest.php b/tests/_files/CoversNothingOnClassTest.php new file mode 100644 index 00000000000..9b361f38ada --- /dev/null +++ b/tests/_files/CoversNothingOnClassTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class CoversNothingOnClassTest extends TestCase +{ + public function testSomething(): void + { + $o = new CoveredClass; + + $o->publicMethod(); + } +} diff --git a/tests/_files/CwdRestoreTest.php b/tests/_files/CwdRestoreTest.php new file mode 100644 index 00000000000..d8f42809ba6 --- /dev/null +++ b/tests/_files/CwdRestoreTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function chdir; +use function sys_get_temp_dir; +use PHPUnit\Framework\TestCase; + +final class CwdRestoreTest extends TestCase +{ + public function testChangesCwd(): void + { + chdir(sys_get_temp_dir()); + + $this->assertTrue(true); + } +} diff --git a/tests/_files/DataProviderDependencyResultTest.php b/tests/_files/DataProviderDependencyResultTest.php new file mode 100644 index 00000000000..752778b10dc --- /dev/null +++ b/tests/_files/DataProviderDependencyResultTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +final class DataProviderDependencyResultTest extends TestCase +{ + public static function providerMethod(): array + { + return [ + [0, 2], + [1, 1], + ['b' => 2, 'a' => 0], + ]; + } + + #[DataProvider('providerMethod')] + #[Depends('testDependency')] + public function testAdd($a, $b, $c): void + { + $this->assertSame(2, $c); + $this->assertSame($c, $a + $b); + } + + public function testDependency(): int + { + $a = 2; + $this->assertSame(2, $a); + + return $a; + } +} diff --git a/tests/_files/DataProviderDependencyTest.php b/tests/_files/DataProviderDependencyTest.php new file mode 100644 index 00000000000..9b14f5d97c7 --- /dev/null +++ b/tests/_files/DataProviderDependencyTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; + +final class DataProviderDependencyTest extends TestCase +{ + public static function provider(): array + { + self::markTestSkipped('Any test with this data provider should be skipped.'); + } + + public function testReference(): void + { + $this->markTestSkipped('This test should be skipped.'); + } + + #[Depends('testReference')] + #[DataProvider('provider')] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/1896')] + public function testDependency($param): void + { + } +} diff --git a/tests/_files/DataProviderDependencyVoidTest.php b/tests/_files/DataProviderDependencyVoidTest.php new file mode 100644 index 00000000000..305b8d82da2 --- /dev/null +++ b/tests/_files/DataProviderDependencyVoidTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +final class DataProviderDependencyVoidTest extends TestCase +{ + public static function provider(): iterable + { + return [ + [0, 0], + [1, 'b' => 1], + ['a' => 2, 'b' => 2], + ['b' => 3, 'a' => 3], + ]; + } + + #[DataProvider('provider')] + #[Depends('testDependency')] + public function testEquality($a, $b): void + { + $this->assertSame($a, $b); + } + + public function testDependency(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/DataProviderExecutionOrderTest.php b/tests/_files/DataProviderExecutionOrderTest.php new file mode 100644 index 00000000000..17f6d69ee97 --- /dev/null +++ b/tests/_files/DataProviderExecutionOrderTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderExecutionOrderTest extends TestCase +{ + public static function dataProviderAdditions(): array + { + return [ + '1+2=3' => [1, 2, 3], + '2+1=3' => [2, 1, 3], + '1+1=3' => [1, 1, 3], + ]; + } + + public function testFirstTestThatAlwaysWorks(): void + { + $this->assertTrue(true); + } + + #[DataProvider('dataProviderAdditions')] + public function testAddNumbersWithDataProvider(int $a, int $b, int $sum): void + { + $this->assertSame($sum, $a + $b); + } + + public function testTestInTheMiddleThatAlwaysWorks(): void + { + $this->assertTrue(true); + } + + #[DataProvider('dataProviderAdditions')] + public function testAddMoreNumbersWithDataProvider(int $a, int $b, int $sum): void + { + $this->assertSame($sum, $a + $b); + } +} diff --git a/tests/_files/DataProviderFilterTest.php b/tests/_files/DataProviderFilterTest.php new file mode 100644 index 00000000000..1c05d2ecae1 --- /dev/null +++ b/tests/_files/DataProviderFilterTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderFilterTest extends TestCase +{ + public static function truthProvider(): array + { + return [ + [true], + [true], + [true], + [true], + ]; + } + + public static function falseProvider(): array + { + return [ + 'false test' => [false], + 'false test 2' => [false], + 'other false test' => [false], + 'other false test2' => [false], + ]; + } + + #[DataProvider('truthProvider')] + public function testTrue($truth): void + { + $this->assertTrue($truth); + } + + #[DataProvider('falseProvider')] + public function testFalse($false): void + { + $this->assertFalse($false); + } +} diff --git a/tests/_files/DataProviderIncompleteTest.php b/tests/_files/DataProviderIncompleteTest.php new file mode 100644 index 00000000000..82df3b64708 --- /dev/null +++ b/tests/_files/DataProviderIncompleteTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderIncompleteTest extends TestCase +{ + public static function providerMethod(): array + { + return [ + [0, 0, 0], + [0, 1, 1], + ]; + } + + public static function incompleteTestProviderMethod(): array + { + self::markTestIncomplete('incomplete'); + } + + #[DataProvider('incompleteTestProviderMethod')] + public function testIncomplete($a, $b, $c): void + { + $this->assertTrue(true); + } + + #[DataProvider('providerMethod')] + public function testAdd($a, $b, $c): void + { + $this->assertEquals($c, $a + $b); + } +} diff --git a/tests/_files/DataProviderIssue2833/FirstTest.php b/tests/_files/DataProviderIssue2833/FirstTest.php new file mode 100644 index 00000000000..165411222e2 --- /dev/null +++ b/tests/_files/DataProviderIssue2833/FirstTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DataProviderIssue2833; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class FirstTest extends TestCase +{ + public static function provide(): array + { + SecondTest::DUMMY; + + return [[true]]; + } + + #[DataProvider('provide')] + public function testFirst($x): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/DataProviderIssue2833/SecondTest.php b/tests/_files/DataProviderIssue2833/SecondTest.php new file mode 100644 index 00000000000..f0635e5d704 --- /dev/null +++ b/tests/_files/DataProviderIssue2833/SecondTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DataProviderIssue2833; + +use PHPUnit\Framework\TestCase; + +class SecondTest extends TestCase +{ + public const DUMMY = 'dummy'; + + public function testSecond(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/DataProviderMethodHasTestAttributeTest.php b/tests/_files/DataProviderMethodHasTestAttributeTest.php new file mode 100644 index 00000000000..29eb18121fc --- /dev/null +++ b/tests/_files/DataProviderMethodHasTestAttributeTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +final class DataProviderMethodHasTestAttributeTest extends TestCase +{ + #[Test] + public static function provider(): array + { + return [[true]]; + } + + #[DataProvider('provider')] + public function testOne(bool $b): void + { + $this->assertTrue($b); + } +} diff --git a/tests/_files/DataProviderMethodNameStartsWithTestTest.php b/tests/_files/DataProviderMethodNameStartsWithTestTest.php new file mode 100644 index 00000000000..922f5036f96 --- /dev/null +++ b/tests/_files/DataProviderMethodNameStartsWithTestTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderMethodNameStartsWithTestTest extends TestCase +{ + public static function testProvider(): array + { + return [[true]]; + } + + #[DataProvider('testProvider')] + public function testOne(bool $b): void + { + $this->assertTrue($b); + } +} diff --git a/tests/_files/DataProviderNamedArgumentsTest.php b/tests/_files/DataProviderNamedArgumentsTest.php new file mode 100644 index 00000000000..facc8dded37 --- /dev/null +++ b/tests/_files/DataProviderNamedArgumentsTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderNamedArgumentsTest extends TestCase +{ + public static function providerMethod() + { + return [ + ['a' => 1, 'b' => 2, 'c' => 3], + ['c' => 3, 'a' => 2, 'b' => 1], + ]; + } + + #[DataProvider('providerMethod')] + public function testAdd($a, $b, $c): void + { + $this->assertEquals($c, $a + $b); + } +} diff --git a/tests/_files/DataProviderRequiresPhpUnitTest.php b/tests/_files/DataProviderRequiresPhpUnitTest.php new file mode 100644 index 00000000000..03a32bd2a4f --- /dev/null +++ b/tests/_files/DataProviderRequiresPhpUnitTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\TestCase; + +final class DataProviderRequiresPhpUnitTest extends TestCase +{ + public static function providerThatThrows(): array + { + throw new Exception('Should have been skipped.'); + } + + public static function validProvider(): array + { + return [[true], [true]]; + } + + public function invalidProvider(): array + { + return [[true], [true]]; + } + + #[RequiresPhpunit('< 10')] + #[DataProvider('invalidProvider')] + public function testWithInvalidDataProvider(bool $param): void + { + $this->assertTrue($param); + } + + #[RequiresPhpunit('>= 10')] + #[DataProvider('validProvider')] + public function testWithValidDataProvider(bool $param): void + { + $this->assertTrue($param); + } + + #[RequiresPhpunit('< 10')] + #[DataProvider('providerThatThrows')] + public function testWithDataProviderThatThrows(): void + { + } + + #[RequiresPhpunit('< 10')] + #[DataProviderExternal(self::class, 'providerThatThrows')] + public function testWithDataProviderExternalThatThrows(): void + { + } +} diff --git a/tests/_files/DataProviderSkippedTest.php b/tests/_files/DataProviderSkippedTest.php new file mode 100644 index 00000000000..939b100290d --- /dev/null +++ b/tests/_files/DataProviderSkippedTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderSkippedTest extends TestCase +{ + public static function providerMethod() + { + return [ + [0, 0, 0], + [0, 1, 1], + ]; + } + + public static function skippedTestProviderMethod(): array + { + self::markTestSkipped('skipped'); + } + + #[DataProvider('skippedTestProviderMethod')] + public function testSkipped($a, $b, $c): void + { + $this->assertTrue(true); + } + + #[DataProvider('providerMethod')] + public function testAdd($a, $b, $c): void + { + $this->assertEquals($c, $a + $b); + } +} diff --git a/tests/_files/DataProviderTest.php b/tests/_files/DataProviderTest.php new file mode 100644 index 00000000000..7fd152cc0e4 --- /dev/null +++ b/tests/_files/DataProviderTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderTest extends TestCase +{ + public static function providerMethod(): array + { + return [ + [0, 0, 0], + [0, 1, 1], + [1, 1, 3], + [1, 0, 1], + ]; + } + + #[DataProvider('providerMethod')] + public function testAdd($a, $b, $c): void + { + $this->assertEquals($c, $a + $b); + } +} diff --git a/tests/_files/DataProviderTooManyArgumentsNoValidationTest.php b/tests/_files/DataProviderTooManyArgumentsNoValidationTest.php new file mode 100644 index 00000000000..9328b38f983 --- /dev/null +++ b/tests/_files/DataProviderTooManyArgumentsNoValidationTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderTooManyArgumentsNoValidationTest extends TestCase +{ + public static function provider(): iterable + { + // correct case, 2nd parameter is not required + yield [true]; + + // correct case + yield [true, true]; + + // incorrect case + yield [true, true, 'Third argument, but test method only has two.']; + } + + #[DataProvider('provider', false)] + public function testMethodHavingTwoParameters(bool $x1, bool $x2 = true): void + { + $this->assertSame($x1, $x2); + } + + #[DataProvider('provider')] + public function testMethodHavingVariadicParameter(bool $x1, ...$rest): void + { + $this->assertTrue($x1); + } +} diff --git a/tests/_files/DataProviderTooManyArgumentsTest.php b/tests/_files/DataProviderTooManyArgumentsTest.php new file mode 100644 index 00000000000..7d94e1e3f02 --- /dev/null +++ b/tests/_files/DataProviderTooManyArgumentsTest.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderTooManyArgumentsTest extends TestCase +{ + public static function provider(): iterable + { + // correct case, 2nd parameter is not required + yield [true]; + + // correct case + yield [true, true]; + + // incorrect case + yield [true, true, 'Third argument, but test method only has two.']; + } + + #[DataProvider('provider')] + public function testMethodHavingTwoParameters(bool $x1, bool $x2 = true): void + { + $this->assertSame($x1, $x2); + } + + #[DataProvider('provider')] + public function testMethodHavingVariadicParameter(bool $x1, ...$rest): void + { + $this->assertTrue($x1); + } + + public function testToNotHaveNoTests(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/DataProviderWithStringKeysTest.php b/tests/_files/DataProviderWithStringKeysTest.php new file mode 100644 index 00000000000..4328f243296 --- /dev/null +++ b/tests/_files/DataProviderWithStringKeysTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderWithStringKeysTest extends TestCase +{ + public static function providerMethod(): array + { + return [ + '0 + 0 = 0' => [0, 0, 0], + '0 + 1 = 1' => [0, 1, 1], + '1 + 1 = 3' => [1, 1, 3], + '1 + 0 = 1' => [1, 0, 1], + ]; + } + + #[DataProvider('providerMethod')] + public function testAdd($a, $b, $c): void + { + $this->assertEquals($c, $a + $b); + } +} diff --git a/tests/_files/DataproviderExecutionOrderTest_result_cache.txt b/tests/_files/DataproviderExecutionOrderTest_result_cache.txt new file mode 100644 index 00000000000..7bb5dbcb0b1 --- /dev/null +++ b/tests/_files/DataproviderExecutionOrderTest_result_cache.txt @@ -0,0 +1 @@ +{"version":2,"defects":{"tests\/end-to-end\/regression\/GitHub\/3396\/issue-3396-test.phpt":3,"MultiDependencyExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+1=3\"":3,"MultiDependencyExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+1=3\"":3,"DataproviderExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+1=3\"":3,"DataproviderExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+1=3\"":3},"times":{"tests\/end-to-end\/regression\/GitHub\/3396\/issue-3396-test.phpt":0.115,"MultiDependencyExecutionOrderTest::testFirstTestThatAlwaysWorks":0,"MultiDependencyExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+2=3\"":0,"MultiDependencyExecutionOrderTest::testAddNumbersWithADataprovider with data set \"2+1=3\"":0,"MultiDependencyExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+1=3\"":0.003,"MultiDependencyExecutionOrderTest::testTestInTheMiddleThatAlwaysWorks":0,"MultiDependencyExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+2=3\"":0,"MultiDependencyExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"2+1=3\"":0,"MultiDependencyExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+1=3\"":0,"DataproviderExecutionOrderTest::testFirstTestThatAlwaysWorks":0.002,"DataproviderExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+2=3\"":0,"DataproviderExecutionOrderTest::testAddNumbersWithADataprovider with data set \"2+1=3\"":0,"DataproviderExecutionOrderTest::testAddNumbersWithADataprovider with data set \"1+1=3\"":0.001,"DataproviderExecutionOrderTest::testTestInTheMiddleThatAlwaysWorks":0,"DataproviderExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+2=3\"":0,"DataproviderExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"2+1=3\"":0,"DataproviderExecutionOrderTest::testAddMoreNumbersWithADataprovider with data set \"1+1=3\"":0}} \ No newline at end of file diff --git a/tests/_files/DependencyInputTest.php b/tests/_files/DependencyInputTest.php new file mode 100644 index 00000000000..9e27f85d2cd --- /dev/null +++ b/tests/_files/DependencyInputTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class DependencyInputTest extends TestCase +{ + public function testDependencyInputAsParameter(string $dependencyInput): void + { + $this->assertEquals('value from TestCaseTest', $dependencyInput); + } +} diff --git a/tests/_files/DependencyOnClassTest.php b/tests/_files/DependencyOnClassTest.php new file mode 100644 index 00000000000..763f9ce1f31 --- /dev/null +++ b/tests/_files/DependencyOnClassTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\TestCase; + +final class DependencyOnClassTest extends TestCase +{ + #[DependsOnClass(DependencySuccessTest::class)] + public function testThatDependsOnASuccessfulClass(): void + { + $this->assertTrue(true); + } + + #[DependsOnClass(DependencyFailureTest::class)] + public function testThatDependsOnAFailingClass(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/DoNoAssertionTestCase.php b/tests/_files/DoNoAssertionTestCase.php new file mode 100644 index 00000000000..0e6747cf4d7 --- /dev/null +++ b/tests/_files/DoNoAssertionTestCase.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class DoNoAssertionTestCase extends TestCase +{ + public function testNothing(): void + { + } +} diff --git a/tests/_files/DoesNotPerformAssertionsButPerformingAssertionsTest.php b/tests/_files/DoesNotPerformAssertionsButPerformingAssertionsTest.php new file mode 100644 index 00000000000..226d7423cf4 --- /dev/null +++ b/tests/_files/DoesNotPerformAssertionsButPerformingAssertionsTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +final class DoesNotPerformAssertionsButPerformingAssertionsTest extends TestCase +{ + #[DoesNotPerformAssertions] + public function testFalseAndTrueAreStillFine(): void + { + $this->assertFalse(false); + $this->assertTrue(true); + } +} diff --git a/tests/_files/DummyBarTest.php b/tests/_files/DummyBarTest.php new file mode 100644 index 00000000000..a06b782ff21 --- /dev/null +++ b/tests/_files/DummyBarTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class DummyBarTest extends TestCase +{ + public function testBarEqualsBar(): void + { + $this->assertEquals('Bar', 'Bar'); + } +} diff --git a/tests/_files/DummyEvent.php b/tests/_files/DummyEvent.php new file mode 100644 index 00000000000..b7de581c688 --- /dev/null +++ b/tests/_files/DummyEvent.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Event\Event; +use PHPUnit\Event\Telemetry\Info; + +final class DummyEvent implements Event +{ + public function telemetryInfo(): Info + { + } + + public function asString(): string + { + } +} diff --git a/tests/_files/DummyException.php b/tests/_files/DummyException.php new file mode 100644 index 00000000000..fce0c0565c4 --- /dev/null +++ b/tests/_files/DummyException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; + +final class DummyException extends Exception +{ +} diff --git a/tests/_files/DummyFooTest.php b/tests/_files/DummyFooTest.php new file mode 100644 index 00000000000..7ef011680ee --- /dev/null +++ b/tests/_files/DummyFooTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class DummyFooTest extends TestCase +{ + public function testFooEqualsFoo(): void + { + $this->assertEquals('Foo', 'Foo'); + } +} diff --git a/tests/_files/DummySubscriber.php b/tests/_files/DummySubscriber.php new file mode 100644 index 00000000000..a0ac832a7e3 --- /dev/null +++ b/tests/_files/DummySubscriber.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Event\Subscriber; + +interface DummySubscriber extends Subscriber +{ + public function notify(DummyEvent $event): void; +} diff --git a/tests/_files/DuplicateKeyDataProviderTest.php b/tests/_files/DuplicateKeyDataProviderTest.php new file mode 100644 index 00000000000..60568a9c732 --- /dev/null +++ b/tests/_files/DuplicateKeyDataProviderTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Generator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DuplicateKeyDataProviderTest extends TestCase +{ + public static function dataProvider(): Generator + { + yield 'foo' => ['foo']; + + yield 'foo' => ['bar']; + } + + #[DataProvider('dataProvider')] + public function test($arg): void + { + } +} diff --git a/tests/_files/DuplicateKeyDataProvidersTest.php b/tests/_files/DuplicateKeyDataProvidersTest.php new file mode 100644 index 00000000000..a44c5578449 --- /dev/null +++ b/tests/_files/DuplicateKeyDataProvidersTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DuplicateKeyDataProvidersTest extends TestCase +{ + public static function dataProvider1(): iterable + { + return [ + 'bar' => [1], + ]; + } + + public static function dataProvider2(): iterable + { + return [ + 'bar' => [2], + ]; + } + + #[DataProvider('dataProvider1')] + #[DataProvider('dataProvider2')] + public function test($value): void + { + $this->assertSame(2, $value); + } +} diff --git a/tests/_files/EmptyDataProviderTest.php b/tests/_files/EmptyDataProviderTest.php new file mode 100644 index 00000000000..b7654d38fe6 --- /dev/null +++ b/tests/_files/EmptyDataProviderTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class EmptyDataProviderTest extends TestCase +{ + public static function providerMethod(): array + { + return []; + } + + #[DataProvider('providerMethod')] + public function testCase(): void + { + } +} diff --git a/tests/_files/EmptyTestCaseTest.php b/tests/_files/EmptyTestCaseTest.php new file mode 100644 index 00000000000..dd4e98980ef --- /dev/null +++ b/tests/_files/EmptyTestCaseTest.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class EmptyTestCaseTest extends TestCase +{ +} diff --git a/tests/_files/Enumeration.php b/tests/_files/Enumeration.php new file mode 100644 index 00000000000..0eb077f465c --- /dev/null +++ b/tests/_files/Enumeration.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +enum Enumeration +{ + case Test; +} diff --git a/tests/_files/EnumerationEquals/Example.php b/tests/_files/EnumerationEquals/Example.php new file mode 100644 index 00000000000..0667f81a8c4 --- /dev/null +++ b/tests/_files/EnumerationEquals/Example.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\EnumerationEquals; + +enum Example +{ + case Foo; + case Bar; +} diff --git a/tests/_files/EnumerationEquals/ExampleInt.php b/tests/_files/EnumerationEquals/ExampleInt.php new file mode 100644 index 00000000000..c5468c4b2b8 --- /dev/null +++ b/tests/_files/EnumerationEquals/ExampleInt.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\EnumerationEquals; + +enum ExampleInt: int +{ + case Foo = 0; + case Bar = 1; +} diff --git a/tests/_files/EnumerationEquals/ExampleString.php b/tests/_files/EnumerationEquals/ExampleString.php new file mode 100644 index 00000000000..e40241ccd33 --- /dev/null +++ b/tests/_files/EnumerationEquals/ExampleString.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\EnumerationEquals; + +enum ExampleString: string +{ + case Foo = 'foo'; + case Bar = 'bar'; +} diff --git a/tests/_files/ExceptionInMockDestructor.php b/tests/_files/ExceptionInMockDestructor.php new file mode 100644 index 00000000000..6be9ff15e1a --- /dev/null +++ b/tests/_files/ExceptionInMockDestructor.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; + +class ExceptionInMockDestructor +{ + public function __destruct() + { + throw new Exception('Some exception.'); + } +} diff --git a/tests/_files/ExceptionInMockDestructorTest.php b/tests/_files/ExceptionInMockDestructorTest.php new file mode 100644 index 00000000000..10ca362150c --- /dev/null +++ b/tests/_files/ExceptionInMockDestructorTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class ExceptionInMockDestructorTest extends TestCase +{ + public function testOne(): void + { + $mock = $this->createMock(ExceptionInMockDestructor::class); + + $this->assertInstanceOf(ExceptionInMockDestructor::class, $mock); + } +} diff --git a/tests/_files/ExceptionStackTest.php b/tests/_files/ExceptionStackTest.php new file mode 100644 index 00000000000..fef5e2df644 --- /dev/null +++ b/tests/_files/ExceptionStackTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use InvalidArgumentException; +use PHPUnit; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +final class ExceptionStackTest extends TestCase +{ + public function testPrintingChildException(): void + { + try { + $this->assertEquals([1], [2], 'message'); + } catch (ExpectationFailedException $e) { + $message = $e->getMessage() . $e->getComparisonFailure()->getDiff(); + + throw new PHPUnit\Framework\Exception("Child exception\n{$message}", 101, $e); + } + } + + public function testNestedExceptions(): void + { + $exceptionThree = new Exception('Three'); + $exceptionTwo = new InvalidArgumentException('Two', 0, $exceptionThree); + $exceptionOne = new Exception('One', 0, $exceptionTwo); + + throw $exceptionOne; + } +} diff --git a/tests/_files/ExceptionThrowingIteratorAggregate.php b/tests/_files/ExceptionThrowingIteratorAggregate.php new file mode 100644 index 00000000000..63c21102fc5 --- /dev/null +++ b/tests/_files/ExceptionThrowingIteratorAggregate.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use IteratorAggregate; +use RuntimeException; +use Traversable; + +final class ExceptionThrowingIteratorAggregate implements IteratorAggregate +{ + public function getIterator(): Traversable + { + throw new RuntimeException; + } +} diff --git a/tests/_files/FaillingDataProviderTest.php b/tests/_files/FaillingDataProviderTest.php new file mode 100644 index 00000000000..2214f4f5985 --- /dev/null +++ b/tests/_files/FaillingDataProviderTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class FaillingDataProviderTest extends TestCase +{ + public static function provideData(): array + { + return [ + 'good1' => [3, 1, 2], + 'good2' => [5, 2, 3], + 'fail1' => [10, 3, 4], + 'good3' => [10, 5, 5], + 'fail2' => [20, 3, 4], + ]; + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + #[DataProvider('provideData')] + public function testWithProvider($sum, $summand, $summmand2): void + { + $this->assertSame($sum, $summand + $summmand2); + } +} diff --git a/tests/_files/Failure.php b/tests/_files/Failure.php new file mode 100644 index 00000000000..80a7284e947 --- /dev/null +++ b/tests/_files/Failure.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Failure extends TestCase +{ + public function testOne(): void + { + $this->fail(); + } +} diff --git a/tests/_files/FailureTest.php b/tests/_files/FailureTest.php new file mode 100644 index 00000000000..deb2b4f4e98 --- /dev/null +++ b/tests/_files/FailureTest.php @@ -0,0 +1,88 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; +use stdClass; + +final class FailureTest extends TestCase +{ + public function testAssertArrayEqualsArray(): void + { + $this->assertEquals([1], [2], 'message'); + } + + public function testAssertIntegerEqualsInteger(): void + { + $this->assertEquals(1, 2, 'message'); + } + + public function testAssertObjectEqualsObject(): void + { + $a = new stdClass; + $a->foo = 'bar'; + + $b = new stdClass; + $b->bar = 'foo'; + + $this->assertEquals($a, $b, 'message'); + } + + public function testAssertNullEqualsString(): void + { + $this->assertEquals(null, 'bar', 'message'); + } + + public function testAssertStringEqualsString(): void + { + $this->assertEquals('foo', 'bar', 'message'); + } + + public function testAssertTextEqualsText(): void + { + $this->assertEquals("foo\nbar\n", "foo\nbaz\n", 'message'); + } + + public function testAssertStringMatchesFormat(): void + { + $this->assertStringMatchesFormat('*%s*', '**', 'message'); + } + + public function testAssertNumericEqualsNumeric(): void + { + $this->assertEquals(1, 2, 'message'); + } + + public function testAssertTextSameText(): void + { + $this->assertSame('foo', 'bar', 'message'); + } + + public function testAssertObjectSameObject(): void + { + $this->assertSame(new stdClass, new stdClass, 'message'); + } + + public function testAssertObjectSameNull(): void + { + $this->assertSame(new stdClass, null, 'message'); + } + + public function testAssertFloatSameFloat(): void + { + $this->assertSame(1.0, 1.5, 'message'); + } + + // Note that due to the implementation of this assertion it counts as 2 asserts + public function testAssertStringMatchesFormatFile(): void + { + $this->assertStringMatchesFormatFile(__DIR__ . '/expectedFileFormat.txt', '...BAR...'); + } +} diff --git a/tests/_files/FileWithIssue.php b/tests/_files/FileWithIssue.php new file mode 100644 index 00000000000..caaa2ce65e7 --- /dev/null +++ b/tests/_files/FileWithIssue.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class FileWithIssue +{ +} diff --git a/tests/_files/Foo.php b/tests/_files/Foo.php new file mode 100644 index 00000000000..f10ca723838 --- /dev/null +++ b/tests/_files/Foo.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class Foo +{ + public function doSomething(Bar $bar) + { + return $bar->doSomethingElse(); + } +} diff --git a/tests/_files/Generator.php b/tests/_files/Generator.php new file mode 100644 index 00000000000..45a1bbf49fc --- /dev/null +++ b/tests/_files/Generator.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Generator; + +use Generator; + +function f(): Generator +{ + yield 0; +} diff --git a/tests/_files/IncompleteTest.php b/tests/_files/IncompleteTest.php new file mode 100644 index 00000000000..3668c8fd121 --- /dev/null +++ b/tests/_files/IncompleteTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class IncompleteTest extends TestCase +{ + public function testIncomplete(): void + { + $this->markTestIncomplete('Test incomplete'); + } +} diff --git a/tests/_files/Inheritance/InheritanceA.php b/tests/_files/Inheritance/InheritanceA.php new file mode 100644 index 00000000000..4de6c644a3e --- /dev/null +++ b/tests/_files/Inheritance/InheritanceA.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +class InheritanceA extends InheritanceB +{ +} diff --git a/tests/_files/Inheritance/InheritanceB.php b/tests/_files/Inheritance/InheritanceB.php new file mode 100644 index 00000000000..93a27b86d8c --- /dev/null +++ b/tests/_files/Inheritance/InheritanceB.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class InheritanceB extends TestCase +{ + public function testSomething(): void + { + } +} diff --git a/tests/_files/InheritedTestCase.php b/tests/_files/InheritedTestCase.php new file mode 100644 index 00000000000..5c379378e0e --- /dev/null +++ b/tests/_files/InheritedTestCase.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class InheritedTestCase extends OneTestCase +{ + public function test2(): void + { + } +} diff --git a/tests/_files/IniTest.php b/tests/_files/IniTest.php new file mode 100644 index 00000000000..2400d0571c8 --- /dev/null +++ b/tests/_files/IniTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function ini_get; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\TestCase; + +final class IniTest extends TestCase +{ + #[PreserveGlobalState(true)] + public function testIni(): void + { + $this->assertEquals('application/x-test', ini_get('default_mimetype')); + } +} diff --git a/tests/_files/InterfaceAsTargetWithAttributeTest.php b/tests/_files/InterfaceAsTargetWithAttributeTest.php new file mode 100644 index 00000000000..98d4eb45b7e --- /dev/null +++ b/tests/_files/InterfaceAsTargetWithAttributeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use Throwable; + +#[CoversClass(Throwable::class)] +#[UsesClass(Throwable::class)] +final class InterfaceAsTargetWithAttributeTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/InvalidClassTargetWithAttributeTest.php b/tests/_files/InvalidClassTargetWithAttributeTest.php new file mode 100644 index 00000000000..067dfcd4ba4 --- /dev/null +++ b/tests/_files/InvalidClassTargetWithAttributeTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass('InvalidClass')] +#[UsesClass('InvalidClass')] +final class InvalidClassTargetWithAttributeTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/InvalidFunctionTargetTest.php b/tests/_files/InvalidFunctionTargetTest.php new file mode 100644 index 00000000000..47943d19ada --- /dev/null +++ b/tests/_files/InvalidFunctionTargetTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\TestCase; + +#[CoversFunction('invalid_function')] +#[UsesFunction('invalid_function')] +final class InvalidFunctionTargetTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/InvokableConstraintAndPipeOperatorTest.php b/tests/_files/InvokableConstraintAndPipeOperatorTest.php new file mode 100644 index 00000000000..6dbab8e00a1 --- /dev/null +++ b/tests/_files/InvokableConstraintAndPipeOperatorTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class InvokableConstraintAndPipeOperatorTest extends TestCase +{ + public function testOne(): void + { + $actual = 'string'; + + $actual |> $this->isString() + |> $this->stringContains('string'); + } +} diff --git a/tests/_files/IsolationTest.php b/tests/_files/IsolationTest.php new file mode 100644 index 00000000000..3a0a76cf640 --- /dev/null +++ b/tests/_files/IsolationTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class IsolationTest extends TestCase +{ + public function testIsInIsolationReturnsFalse(): void + { + $this->assertFalse($this->isInIsolation()); + } + + public function testIsInIsolationReturnsTrue(): void + { + $this->assertTrue($this->isInIsolation()); + } +} diff --git a/Tests/_files/JsonData/arrayObject.js b/tests/_files/JsonData/arrayObject.json similarity index 100% rename from Tests/_files/JsonData/arrayObject.js rename to tests/_files/JsonData/arrayObject.json diff --git a/Tests/_files/JsonData/simpleObject.js b/tests/_files/JsonData/simpleObject.json similarity index 100% rename from Tests/_files/JsonData/simpleObject.js rename to tests/_files/JsonData/simpleObject.json diff --git a/tests/_files/LargeGroupAttributesTest.php b/tests/_files/LargeGroupAttributesTest.php new file mode 100644 index 00000000000..f8f2a316270 --- /dev/null +++ b/tests/_files/LargeGroupAttributesTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\TestCase; + +#[Large] +final class LargeGroupAttributesTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/MediumGroupAttributesTest.php b/tests/_files/MediumGroupAttributesTest.php new file mode 100644 index 00000000000..49cdd19a274 --- /dev/null +++ b/tests/_files/MediumGroupAttributesTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; + +#[Medium] +final class MediumGroupAttributesTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/src/Example.php b/tests/_files/Metadata/Attribute/src/Example.php new file mode 100644 index 00000000000..5e380bbd6a7 --- /dev/null +++ b/tests/_files/Metadata/Attribute/src/Example.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +final class Example +{ + public function method(): void + { + } +} + +function f(): void +{ +} diff --git a/tests/_files/Metadata/Attribute/src/ExampleTrait.php b/tests/_files/Metadata/Attribute/src/ExampleTrait.php new file mode 100644 index 00000000000..8b8d743a1a3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/src/ExampleTrait.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +trait ExampleTrait +{ +} diff --git a/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnClassTest.php b/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnClassTest.php new file mode 100644 index 00000000000..6c9523e0cc1 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnClassTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; + +#[AllowMockObjectsWithoutExpectations] +final class AllowMockObjectsWithoutExpectationsOnClassTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnMethodTest.php b/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnMethodTest.php new file mode 100644 index 00000000000..042e7b91274 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/AllowMockObjectsWithoutExpectationsOnMethodTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; + +final class AllowMockObjectsWithoutExpectationsOnMethodTest extends TestCase +{ + #[AllowMockObjectsWithoutExpectations] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/AnotherTest.php b/tests/_files/Metadata/Attribute/tests/AnotherTest.php new file mode 100644 index 00000000000..2be4ab1fe23 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/AnotherTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\TestCase; + +final class AnotherTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/BackupGlobalsTest.php b/tests/_files/Metadata/Attribute/tests/BackupGlobalsTest.php new file mode 100644 index 00000000000..2405a20b7da --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/BackupGlobalsTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup; +use PHPUnit\Framework\TestCase; + +#[BackupGlobals(true)] +#[ExcludeGlobalVariableFromBackup('foo')] +final class BackupGlobalsTest extends TestCase +{ + #[BackupGlobals(false)] + #[ExcludeGlobalVariableFromBackup('bar')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/BackupStaticPropertiesTest.php b/tests/_files/Metadata/Attribute/tests/BackupStaticPropertiesTest.php new file mode 100644 index 00000000000..4f239206805 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/BackupStaticPropertiesTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\ExcludeStaticPropertyFromBackup; +use PHPUnit\Framework\TestCase; + +#[BackupStaticProperties(true)] +#[ExcludeStaticPropertyFromBackup('className', 'propertyName')] +final class BackupStaticPropertiesTest extends TestCase +{ + #[BackupStaticProperties(false)] + #[ExcludeStaticPropertyFromBackup('anotherClassName', 'propertyName')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/CoversNothingTest.php b/tests/_files/Metadata/Attribute/tests/CoversNothingTest.php new file mode 100644 index 00000000000..bd5b02a1e97 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/CoversNothingTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class CoversNothingTest extends TestCase +{ + #[CoversNothing] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/CoversTest.php b/tests/_files/Metadata/Attribute/tests/CoversTest.php new file mode 100644 index 00000000000..c8eed04d646 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/CoversTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\CoversClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversNamespace; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\TestCase; + +#[CoversNamespace('PHPUnit\TestFixture\Metadata\Attribute')] +#[CoversClass(Example::class)] +#[CoversClassesThatExtendClass(Example::class)] +#[CoversClassesThatImplementInterface(Example::class)] +#[CoversTrait(ExampleTrait::class)] +#[CoversMethod(Example::class, 'method')] +#[CoversFunction('f')] +final class CoversTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/DependencyTest.php b/tests/_files/Metadata/Attribute/tests/DependencyTest.php new file mode 100644 index 00000000000..886a95bf106 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/DependencyTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\Attributes\DependsExternalUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsExternalUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsUsingShallowClone; +use PHPUnit\Framework\TestCase; + +final class DependencyTest extends TestCase +{ + #[Depends('testOne')] + public function testOne(): void + { + } + + #[DependsUsingDeepClone('testOne')] + public function testTwo(): void + { + } + + #[DependsUsingShallowClone('testOne')] + public function testThree(): void + { + } + + #[DependsExternal(AnotherTest::class, 'testOne')] + public function testFour(): void + { + } + + #[DependsExternalUsingDeepClone(AnotherTest::class, 'testOne')] + public function testFive(): void + { + } + + #[DependsExternalUsingShallowClone(AnotherTest::class, 'testOne')] + public function testSix(): void + { + } + + #[DependsOnClass(AnotherTest::class)] + public function testSeven(): void + { + } + + #[DependsOnClassUsingDeepClone(AnotherTest::class)] + public function testEight(): void + { + } + + #[DependsOnClassUsingShallowClone(AnotherTest::class)] + public function testNine(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/DisableReturnValueGenerationForTestDoublesTest.php b/tests/_files/Metadata/Attribute/tests/DisableReturnValueGenerationForTestDoublesTest.php new file mode 100644 index 00000000000..6a8537248b3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/DisableReturnValueGenerationForTestDoublesTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\TestCase; + +#[DisableReturnValueGenerationForTestDoubles] +final class DisableReturnValueGenerationForTestDoublesTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/DoesNotPerformAssertionsTest.php b/tests/_files/Metadata/Attribute/tests/DoesNotPerformAssertionsTest.php new file mode 100644 index 00000000000..a8b2dc29f1d --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/DoesNotPerformAssertionsTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +#[DoesNotPerformAssertions] +final class DoesNotPerformAssertionsTest extends TestCase +{ + #[DoesNotPerformAssertions] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/DuplicateSmallAttributeTest.php b/tests/_files/Metadata/Attribute/tests/DuplicateSmallAttributeTest.php new file mode 100644 index 00000000000..218c4bd8fdf --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/DuplicateSmallAttributeTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +#[Small] +final class DuplicateSmallAttributeTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/DuplicateTestAttributeTest.php b/tests/_files/Metadata/Attribute/tests/DuplicateTestAttributeTest.php new file mode 100644 index 00000000000..b5214201fed --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/DuplicateTestAttributeTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +final class DuplicateTestAttributeTest extends TestCase +{ + #[Test] + #[Test] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/GroupTest.php b/tests/_files/Metadata/Attribute/tests/GroupTest.php new file mode 100644 index 00000000000..2bfed5d7dfa --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/GroupTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; + +#[Group('group')] +#[Ticket('ticket')] +final class GroupTest extends TestCase +{ + #[Group('another-group')] + #[Ticket('another-ticket')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsClassTest.php b/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsClassTest.php new file mode 100644 index 00000000000..b3dc8367d02 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsClassTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; + +#[IgnoreDeprecations] +final class IgnoreDeprecationsClassTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsMethodTest.php b/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsMethodTest.php new file mode 100644 index 00000000000..4ae80b3c490 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/IgnoreDeprecationsMethodTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; + +final class IgnoreDeprecationsMethodTest extends TestCase +{ + #[IgnoreDeprecations] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsClassTest.php b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsClassTest.php new file mode 100644 index 00000000000..1d1cf684501 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsClassTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\TestCase; + +#[IgnorePhpunitDeprecations] +final class IgnorePhpunitDeprecationsClassTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsMethodTest.php b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsMethodTest.php new file mode 100644 index 00000000000..1726a374883 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitDeprecationsMethodTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\TestCase; + +final class IgnorePhpunitDeprecationsMethodTest extends TestCase +{ + #[IgnorePhpunitDeprecations] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/IgnorePhpunitWarningsTest.php b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitWarningsTest.php new file mode 100644 index 00000000000..57580c6b4eb --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/IgnorePhpunitWarningsTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\IgnorePhpunitWarnings; +use PHPUnit\Framework\TestCase; + +final class IgnorePhpunitWarningsTest extends TestCase +{ + #[IgnorePhpunitWarnings] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/Metadata/Attribute/tests/LargeTest.php b/tests/_files/Metadata/Attribute/tests/LargeTest.php new file mode 100644 index 00000000000..92e87e1bf51 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/LargeTest.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\TestCase; + +#[Large] +final class LargeTest extends TestCase +{ +} diff --git a/tests/_files/Metadata/Attribute/tests/MediumTest.php b/tests/_files/Metadata/Attribute/tests/MediumTest.php new file mode 100644 index 00000000000..2f4de138695 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/MediumTest.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; + +#[Medium] +final class MediumTest extends TestCase +{ +} diff --git a/tests/_files/Metadata/Attribute/tests/NonPhpunitAttribute.php b/tests/_files/Metadata/Attribute/tests/NonPhpunitAttribute.php new file mode 100644 index 00000000000..ebb62c5e814 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/NonPhpunitAttribute.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use Attribute; + +#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)] +final class NonPhpunitAttribute +{ +} diff --git a/tests/_files/Metadata/Attribute/tests/NonPhpunitAttributeTest.php b/tests/_files/Metadata/Attribute/tests/NonPhpunitAttributeTest.php new file mode 100644 index 00000000000..e4f1eb216cd --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/NonPhpunitAttributeTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\TestCase; + +#[NonPhpunitAttribute] +final class NonPhpunitAttributeTest extends TestCase +{ + #[NonPhpunitAttribute] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/PhpunitAttributeThatDoesNotExistTest.php b/tests/_files/Metadata/Attribute/tests/PhpunitAttributeThatDoesNotExistTest.php new file mode 100644 index 00000000000..067a9df2f2e --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/PhpunitAttributeThatDoesNotExistTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\PhpunitAttributeThatDoesNotExist; +use PHPUnit\Framework\TestCase; + +#[PhpunitAttributeThatDoesNotExist] +final class PhpunitAttributeThatDoesNotExistTest extends TestCase +{ + #[PhpunitAttributeThatDoesNotExist] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/PreserveGlobalStateTest.php b/tests/_files/Metadata/Attribute/tests/PreserveGlobalStateTest.php new file mode 100644 index 00000000000..e0a284af2e0 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/PreserveGlobalStateTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\TestCase; + +#[PreserveGlobalState(true)] +final class PreserveGlobalStateTest extends TestCase +{ + #[PreserveGlobalState(false)] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/ProcessIsolationTest.php b/tests/_files/Metadata/Attribute/tests/ProcessIsolationTest.php new file mode 100644 index 00000000000..948e7a038cd --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/ProcessIsolationTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class ProcessIsolationTest extends TestCase +{ + #[RunInSeparateProcess] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresEnvironmentVariableTest.php b/tests/_files/Metadata/Attribute/tests/RequiresEnvironmentVariableTest.php new file mode 100644 index 00000000000..96fefede969 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresEnvironmentVariableTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\TestCase; + +#[RequiresEnvironmentVariable('foo', 'bar')] +final class RequiresEnvironmentVariableTest extends TestCase +{ + #[RequiresEnvironmentVariable('foo')] + #[RequiresEnvironmentVariable('bar', 'baz')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresFunctionTest.php b/tests/_files/Metadata/Attribute/tests/RequiresFunctionTest.php new file mode 100644 index 00000000000..faf1289b15f --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresFunctionTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresFunction; +use PHPUnit\Framework\TestCase; + +#[RequiresFunction('f')] +final class RequiresFunctionTest extends TestCase +{ + #[RequiresFunction('g')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresMethodTest.php b/tests/_files/Metadata/Attribute/tests/RequiresMethodTest.php new file mode 100644 index 00000000000..faea6e8a1db --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresMethodTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\TestCase; + +#[RequiresMethod('ClassName', 'methodName')] +final class RequiresMethodTest extends TestCase +{ + #[RequiresMethod('AnotherClassName', 'anotherMethodName')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemFamilyTest.php b/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemFamilyTest.php new file mode 100644 index 00000000000..24b190879f3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemFamilyTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; +use PHPUnit\Framework\TestCase; + +#[RequiresOperatingSystemFamily('Linux')] +final class RequiresOperatingSystemFamilyTest extends TestCase +{ + #[RequiresOperatingSystemFamily('Linux')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemTest.php b/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemTest.php new file mode 100644 index 00000000000..b62fe6121b3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresOperatingSystemTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; +use PHPUnit\Framework\TestCase; + +#[RequiresOperatingSystem('Linux')] +final class RequiresOperatingSystemTest extends TestCase +{ + #[RequiresOperatingSystem('Linux')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresPhpExtensionTest.php b/tests/_files/Metadata/Attribute/tests/RequiresPhpExtensionTest.php new file mode 100644 index 00000000000..34ba5c39fb3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresPhpExtensionTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpExtension('foo', '>= 1.0')] +final class RequiresPhpExtensionTest extends TestCase +{ + #[RequiresPhpExtension('bar', '>= 2.0')] + public function testOne(): void + { + } + + #[RequiresPhpExtension('baz', '^1.0')] + public function testTwo(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresPhpTest.php b/tests/_files/Metadata/Attribute/tests/RequiresPhpTest.php new file mode 100644 index 00000000000..c6bef15dbf1 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresPhpTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\TestCase; + +#[RequiresPhp('8.0.0')] +final class RequiresPhpTest extends TestCase +{ + #[RequiresPhp('^8.0')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresPhpunitExtensionTest.php b/tests/_files/Metadata/Attribute/tests/RequiresPhpunitExtensionTest.php new file mode 100644 index 00000000000..360b01996b3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresPhpunitExtensionTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresPhpunitExtension; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpunitExtension(SomeExtension::class)] +final class RequiresPhpunitExtensionTest extends TestCase +{ + #[RequiresPhpunitExtension(SomeExtension::class)] + #[RequiresPhpunitExtension(SomeOtherExtension::class)] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresPhpunitTest.php b/tests/_files/Metadata/Attribute/tests/RequiresPhpunitTest.php new file mode 100644 index 00000000000..5570ef5113f --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresPhpunitTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpunit('>= 10.0.0')] +final class RequiresPhpunitTest extends TestCase +{ + #[RequiresPhpunit('^10.0')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/RequiresSettingTest.php b/tests/_files/Metadata/Attribute/tests/RequiresSettingTest.php new file mode 100644 index 00000000000..2bf825649c3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/RequiresSettingTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\RequiresSetting; +use PHPUnit\Framework\TestCase; + +#[RequiresSetting('setting', 'value')] +final class RequiresSettingTest extends TestCase +{ + #[RequiresSetting('another-setting', 'another-value')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/SmallTest.php b/tests/_files/Metadata/Attribute/tests/SmallTest.php new file mode 100644 index 00000000000..566f67e6eba --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/SmallTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +#[Small] +final class SmallTest extends TestCase +{ + #[BeforeClass] + public function beforeTests(): void + { + } + + #[Before] + public function beforeTest(): void + { + } + + #[PreCondition] + public function preCondition(): void + { + } + + #[Test] + public function one(): void + { + } + + #[DataProvider('provider')] + public function testWithDataProvider(): void + { + } + + #[DataProviderExternal(self::class, 'provider')] + public function testWithDataProviderExternal(): void + { + } + + #[PostCondition] + public function postCondition(): void + { + } + + #[After] + public function afterTest(): void + { + } + + #[AfterClass] + public function afterTests(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/TestDoxTest.php b/tests/_files/Metadata/Attribute/tests/TestDoxTest.php new file mode 100644 index 00000000000..98f5a9b5fa6 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/TestDoxTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\Attributes\TestDoxFormatterExternal; +use PHPUnit\Framework\TestCase; + +#[TestDox('text')] +final class TestDoxTest extends TestCase +{ + #[TestDox('text')] + public function testOne(): void + { + } + + #[TestDoxFormatter('methodName')] + public function testTwo(): void + { + } + + #[TestDoxFormatterExternal('ClassName', 'methodName')] + public function testThree(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/TestWithInvalidValueTest.php b/tests/_files/Metadata/Attribute/tests/TestWithInvalidValueTest.php new file mode 100644 index 00000000000..aa3954aa9d9 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/TestWithInvalidValueTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\TestCase; + +final class TestWithInvalidValueTest extends TestCase +{ + #[TestWithJson('false')] + public function testOne($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/Metadata/Attribute/tests/TestWithTest.php b/tests/_files/Metadata/Attribute/tests/TestWithTest.php new file mode 100644 index 00000000000..5ed7dd01f1b --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/TestWithTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\TestCase; + +final class TestWithTest extends TestCase +{ + #[TestWith([1, 2, 3])] + public function testOne($one, $two, $three): void + { + $this->assertTrue(true); + } + + #[TestWith([1, 2, 3], 'Name1')] + public function testOneWithName($one, $two = null, $three = null): void + { + $this->assertTrue(true); + } + + #[TestWithJson('[1, 2, 3]')] + public function testTwo($one, $two, $three): void + { + $this->assertTrue(true); + } + + #[TestWithJson('[1, 2, 3]', 'Name2')] + public function testTwoWithName($one, $two, $three): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/Metadata/Attribute/tests/TestWithTooManyValuesTest.php b/tests/_files/Metadata/Attribute/tests/TestWithTooManyValuesTest.php new file mode 100644 index 00000000000..4fe79a44af3 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/TestWithTooManyValuesTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\TestCase; + +final class TestWithTooManyValuesTest extends TestCase +{ + #[TestWith([1, 2, 3])] + public function testOne($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/Metadata/Attribute/tests/UsesTest.php b/tests/_files/Metadata/Attribute/tests/UsesTest.php new file mode 100644 index 00000000000..0333fdb525d --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/UsesTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\Attributes\UsesClassesThatExtendClass; +use PHPUnit\Framework\Attributes\UsesClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\Attributes\UsesMethod; +use PHPUnit\Framework\Attributes\UsesNamespace; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\TestCase; + +#[UsesNamespace('PHPUnit\TestFixture\Metadata\Attribute')] +#[UsesClass(Example::class)] +#[UsesClassesThatExtendClass(Example::class)] +#[UsesClassesThatImplementInterface(Example::class)] +#[UsesTrait(ExampleTrait::class)] +#[UsesMethod(Example::class, 'method')] +#[UsesFunction('f')] +final class UsesTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/WithEnvironmentVariableTest.php b/tests/_files/Metadata/Attribute/tests/WithEnvironmentVariableTest.php new file mode 100644 index 00000000000..1624ff1419d --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/WithEnvironmentVariableTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\TestCase; + +#[WithEnvironmentVariable('foo', 'bar')] +final class WithEnvironmentVariableTest extends TestCase +{ + #[WithEnvironmentVariable('foo')] + #[WithEnvironmentVariable('bar', 'baz')] + public function testOne(): void + { + } +} diff --git a/tests/_files/Metadata/Attribute/tests/WithoutErrorHandlerTest.php b/tests/_files/Metadata/Attribute/tests/WithoutErrorHandlerTest.php new file mode 100644 index 00000000000..7381f1a8337 --- /dev/null +++ b/tests/_files/Metadata/Attribute/tests/WithoutErrorHandlerTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Metadata\Attribute; + +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Framework\TestCase; + +final class WithoutErrorHandlerTest extends TestCase +{ + #[WithoutErrorHandler] + public function testOne(): void + { + } +} diff --git a/tests/_files/MockTestInterface.php b/tests/_files/MockTestInterface.php new file mode 100644 index 00000000000..95fee63faa7 --- /dev/null +++ b/tests/_files/MockTestInterface.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +interface MockTestInterface +{ + public function returnAnything(); + + public function returnAnythingElse(); +} diff --git a/tests/_files/Mockable.php b/tests/_files/Mockable.php new file mode 100644 index 00000000000..da9d1568ecc --- /dev/null +++ b/tests/_files/Mockable.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +class Mockable +{ + public $constructorArgs; + public $cloned; + + public function __construct($arg1 = null, $arg2 = null) + { + $this->constructorArgs = [$arg1, $arg2]; + } + + public function __clone() + { + $this->cloned = true; + } + + public function mockableMethod() + { + // something different from NULL + return true; + } + + public function anotherMockableMethod() + { + // something different from NULL + return true; + } +} diff --git a/tests/_files/MultiDependencyTest.php b/tests/_files/MultiDependencyTest.php new file mode 100644 index 00000000000..c6b7e207592 --- /dev/null +++ b/tests/_files/MultiDependencyTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\TestCase; + +class MultiDependencyTest extends TestCase +{ + public function testOne() + { + $this->assertTrue(true); + + return 'foo'; + } + + public function testTwo() + { + $this->assertTrue(true); + + return 'bar'; + } + + #[Depends('testOne')] + #[Depends('testTwo')] + public function testThree($a, $b): void + { + $this->assertEquals('foo', $a); + $this->assertEquals('bar', $b); + } + + #[DependsExternal(self::class, 'testThree')] + public function testFour(): void + { + $this->assertTrue(true); + } + + public function testFive(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/MultipleDataProviderTest.php b/tests/_files/MultipleDataProviderTest.php new file mode 100644 index 00000000000..e0cc9bc688d --- /dev/null +++ b/tests/_files/MultipleDataProviderTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use ArrayIterator; +use ArrayObject; +use Generator; +use Iterator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class MultipleDataProviderTest extends TestCase +{ + public static function providerA(): array + { + return [ + ['ok', null, null], + ['ok', null, null], + ['ok', null, null], + ]; + } + + public static function providerB(): array + { + return [ + [null, 'ok', null], + [null, 'ok', null], + [null, 'ok', null], + ]; + } + + public static function providerC(): array + { + return [ + [null, null, 'ok'], + [null, null, 'ok'], + [null, null, 'ok'], + ]; + } + + public static function providerD(): Generator + { + yield ['ok', null, null]; + + yield ['ok', null, null]; + + yield ['ok', null, null]; + } + + public static function providerE(): Generator + { + yield [null, 'ok', null]; + + yield [null, 'ok', null]; + + yield [null, 'ok', null]; + } + + public static function providerF(): ArrayIterator|Iterator + { + $object = new ArrayObject( + [ + [null, null, 'ok'], + [null, null, 'ok'], + [null, null, 'ok'], + ], + ); + + return $object->getIterator(); + } + + #[DataProvider('providerA')] + #[DataProvider('providerB')] + #[DataProvider('providerC')] + public function testOne($one, $two, $three): void + { + } + + #[DataProvider('providerD')] + #[DataProvider('providerE')] + #[DataProvider('providerF')] + public function testTwo($one, $two, $three): void + { + } +} diff --git a/tests/_files/NamespaceCoveredFunction.php b/tests/_files/NamespaceCoveredFunction.php new file mode 100644 index 00000000000..554bb9cccca --- /dev/null +++ b/tests/_files/NamespaceCoveredFunction.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +function func() +{ + return true; +} diff --git a/tests/_files/NoArgTestCaseTest.php b/tests/_files/NoArgTestCaseTest.php new file mode 100644 index 00000000000..95d914f4b4d --- /dev/null +++ b/tests/_files/NoArgTestCaseTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NoArgTestCaseTest extends TestCase +{ + public function testNothing(): void + { + } +} diff --git a/tests/_files/NoCoverageAttributesTest.php b/tests/_files/NoCoverageAttributesTest.php new file mode 100644 index 00000000000..422f56e7e80 --- /dev/null +++ b/tests/_files/NoCoverageAttributesTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NoCoverageAttributesTest extends TestCase +{ + public function testSomething(): void + { + $o = new CoveredClass; + + $o->publicMethod(); + } +} diff --git a/tests/_files/NoGroupsMetadataTest.php b/tests/_files/NoGroupsMetadataTest.php new file mode 100644 index 00000000000..d4b4d44d65e --- /dev/null +++ b/tests/_files/NoGroupsMetadataTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NoGroupsMetadataTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/NoTestCase.php b/tests/_files/NoTestCase.php new file mode 100644 index 00000000000..83498f1dcaa --- /dev/null +++ b/tests/_files/NoTestCase.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class NoTestCase +{ +} diff --git a/tests/_files/NoTestCases.php b/tests/_files/NoTestCases.php new file mode 100644 index 00000000000..d885f95d373 --- /dev/null +++ b/tests/_files/NoTestCases.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NoTestCases extends TestCase +{ + public function noTestCase(): void + { + } +} diff --git a/tests/_files/NotPublicTestCase.php b/tests/_files/NotPublicTestCase.php new file mode 100644 index 00000000000..651118f9263 --- /dev/null +++ b/tests/_files/NotPublicTestCase.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NotPublicTestCase extends TestCase +{ + public function testPublic(): void + { + } + + protected function testNotPublic(): void + { + } +} diff --git a/tests/_files/NothingTest.php b/tests/_files/NothingTest.php new file mode 100644 index 00000000000..3c37b9e3572 --- /dev/null +++ b/tests/_files/NothingTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class NothingTest extends TestCase +{ + public function testNothing(): void + { + } +} diff --git a/tests/_files/ObjectEquals/ValueObject.php b/tests/_files/ObjectEquals/ValueObject.php new file mode 100644 index 00000000000..49449eea158 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObject.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObject +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other): bool + { + return $this->asInt() === $other->asInt(); + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatAcceptsTooManyArguments.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatAcceptsTooManyArguments.php new file mode 100644 index 00000000000..dae003c5255 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatAcceptsTooManyArguments.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodThatAcceptsTooManyArguments +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other, self $another): bool + { + return false; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotAcceptArguments.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotAcceptArguments.php new file mode 100644 index 00000000000..c6e78ebd962 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotAcceptArguments.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodThatDoesNotAcceptArguments +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(): bool + { + return false; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType.php new file mode 100644 index 00000000000..36ce99b3e47 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals($other): bool + { + return $this->asInt() === $other->asInt(); + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasIncompatibleParameterType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasIncompatibleParameterType.php new file mode 100644 index 00000000000..60e00f0265b --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasIncompatibleParameterType.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +use stdClass; + +final class ValueObjectWithEqualsMethodThatHasIncompatibleParameterType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(stdClass $other): bool + { + return false; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasUnionParameterType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasUnionParameterType.php new file mode 100644 index 00000000000..1b157ee682b --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodThatHasUnionParameterType.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +use stdClass; + +final class ValueObjectWithEqualsMethodThatHasUnionParameterType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self|stdClass $other): bool + { + return false; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithNullableReturnType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithNullableReturnType.php new file mode 100644 index 00000000000..a93dd17bcc4 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithNullableReturnType.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodWithNullableReturnType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other): ?bool + { + return null; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithUnionReturnType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithUnionReturnType.php new file mode 100644 index 00000000000..e5baff4844f --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithUnionReturnType.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodWithUnionReturnType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other): bool|int + { + return 0; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithVoidReturnType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithVoidReturnType.php new file mode 100644 index 00000000000..ddc11c1fd00 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithVoidReturnType.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodWithVoidReturnType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other): void + { + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithoutReturnType.php b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithoutReturnType.php new file mode 100644 index 00000000000..102c12cc12a --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithEqualsMethodWithoutReturnType.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithEqualsMethodWithoutReturnType +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function equals(self $other) + { + return $this->asInt() === $other->asInt(); + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/ObjectEquals/ValueObjectWithoutEqualsMethod.php b/tests/_files/ObjectEquals/ValueObjectWithoutEqualsMethod.php new file mode 100644 index 00000000000..1a8f935b475 --- /dev/null +++ b/tests/_files/ObjectEquals/ValueObjectWithoutEqualsMethod.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ObjectEquals; + +final class ValueObjectWithoutEqualsMethod +{ + private $value; + + public function __construct(int $value) + { + $this->value = $value; + } + + public function asInt(): int + { + return $this->value; + } +} diff --git a/tests/_files/OneClassPerFile/TwoClassesValid.php b/tests/_files/OneClassPerFile/TwoClassesValid.php new file mode 100644 index 00000000000..cd335d64180 --- /dev/null +++ b/tests/_files/OneClassPerFile/TwoClassesValid.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class TwoClassesValid extends Foobar +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} + +class Foobar extends TestCase +{ +} diff --git a/tests/_files/OneClassPerFile/phpunit.xml b/tests/_files/OneClassPerFile/phpunit.xml new file mode 100644 index 00000000000..a9ed416d738 --- /dev/null +++ b/tests/_files/OneClassPerFile/phpunit.xml @@ -0,0 +1,9 @@ + + + + + wrongClassName + + + diff --git a/tests/_files/OneClassPerFile/wrongClassName/WrongClassNameTest.php b/tests/_files/OneClassPerFile/wrongClassName/WrongClassNameTest.php new file mode 100644 index 00000000000..c16a8a960d4 --- /dev/null +++ b/tests/_files/OneClassPerFile/wrongClassName/WrongClassNameTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class WrongClassNameBar extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/OneTestCase.php b/tests/_files/OneTestCase.php new file mode 100644 index 00000000000..e0e3a603ae4 --- /dev/null +++ b/tests/_files/OneTestCase.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class OneTestCase extends TestCase +{ + public function noTestCase(): void + { + } + + public function testCase($arg = ''): void + { + } +} diff --git a/tests/_files/OutputTest.php b/tests/_files/OutputTest.php new file mode 100644 index 00000000000..2719fb7bf82 --- /dev/null +++ b/tests/_files/OutputTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class OutputTest extends TestCase +{ + public function testExpectOutputStringFooActualFoo(): void + { + $this->expectOutputString('foo'); + print 'foo'; + } + + public function testExpectOutputStringFooActualBar(): void + { + $this->expectOutputString('foo'); + print 'bar'; + } + + public function testExpectOutputRegexFooActualFoo(): void + { + $this->expectOutputRegex('/foo/'); + print 'foo'; + } + + public function testExpectOutputRegexFooActualBar(): void + { + $this->expectOutputRegex('/foo/'); + print 'bar'; + } +} diff --git a/tests/_files/ParentClassWithPrivateAttributes.php b/tests/_files/ParentClassWithPrivateAttributes.php new file mode 100644 index 00000000000..0c823151946 --- /dev/null +++ b/tests/_files/ParentClassWithPrivateAttributes.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +class ParentClassWithPrivateAttributes +{ + private static $privateStaticParentAttribute = 'foo'; + private $privateParentAttribute = 'bar'; +} diff --git a/tests/_files/ParentClassWithProtectedAttributes.php b/tests/_files/ParentClassWithProtectedAttributes.php new file mode 100644 index 00000000000..c1d4fb2dde6 --- /dev/null +++ b/tests/_files/ParentClassWithProtectedAttributes.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +class ParentClassWithProtectedAttributes extends ParentClassWithPrivateAttributes +{ + protected static $protectedStaticParentAttribute = 'foo'; + protected $protectedParentAttribute = 'bar'; +} diff --git a/tests/_files/RecordingSubscriber.php b/tests/_files/RecordingSubscriber.php new file mode 100644 index 00000000000..dbb348297db --- /dev/null +++ b/tests/_files/RecordingSubscriber.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function count; +use function end; +use PHPUnit\Event; + +abstract class RecordingSubscriber +{ + /** + * @var array + */ + private array $events = []; + + final public function recordedEventCount(): int + { + return count($this->events); + } + + final public function lastRecordedEvent(): ?Event\Event + { + if ([] === $this->events) { + return null; + } + + return end($this->events); + } + + final protected function record($event): void + { + $this->events[] = $event; + } +} diff --git a/tests/_files/RequirementsEnvironmentVariableTest.php b/tests/_files/RequirementsEnvironmentVariableTest.php new file mode 100644 index 00000000000..dac8f0249ce --- /dev/null +++ b/tests/_files/RequirementsEnvironmentVariableTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\TestCase; + +final class RequirementsEnvironmentVariableTest extends TestCase +{ + #[RequiresEnvironmentVariable('FOO', 'bar')] + #[RequiresEnvironmentVariable('BAR')] + #[RequiresEnvironmentVariable('BAZ')] + public function testRequiresEnvironmentVariable(): void + { + } +} diff --git a/tests/_files/RequirementsTest.php b/tests/_files/RequirementsTest.php new file mode 100644 index 00000000000..ccd722f450a --- /dev/null +++ b/tests/_files/RequirementsTest.php @@ -0,0 +1,373 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\RequiresFunction; +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RequiresPhpunitExtension; +use PHPUnit\Framework\Attributes\RequiresSetting; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; +use ReflectionMethod; + +final class RequirementsTest extends TestCase +{ + public function testOne(): void + { + } + + #[RequiresPhpunit('>= 1.0')] + public function testTwo(): void + { + } + + #[RequiresPhp('>= 2.0')] + public function testThree(): void + { + } + + #[RequiresPhpunit('>= 2.0')] + #[RequiresPhp('>= 1.0')] + public function testFour(): void + { + } + + #[RequiresPhp('5.4.0RC6')] + public function testFive(): void + { + } + + #[RequiresPhp('5.4.0-alpha1')] + public function testSix(): void + { + } + + #[RequiresPhp('5.4.0beta2')] + public function testSeven(): void + { + } + + #[RequiresPhp('5.4-dev')] + public function testEight(): void + { + } + + #[RequiresFunction('testFunc')] + public function testNine(): void + { + } + + #[RequiresFunction('testFunc2')] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/3459')] + public function testRequiresFunctionWithDigit(): void + { + } + + #[RequiresPhpExtension('testExt')] + public function testTen(): void + { + } + + #[RequiresOperatingSystem('SunOS')] + #[RequiresOperatingSystemFamily('Solaris')] + public function testEleven(): void + { + } + + #[RequiresPhp('99-dev')] + #[RequiresPhpunit('99-dev')] + #[RequiresOperatingSystem('DOESNOTEXIST')] + #[RequiresOperatingSystemFamily('DOESNOTEXIST')] + #[RequiresFunction('testFuncOne')] + #[RequiresFunction('testFunc2')] + #[RequiresMethod('DoesNotExist', 'doesNotExist')] + #[RequiresPhpExtension('testExtOne')] + #[RequiresPhpExtension('testExt2')] + #[RequiresPhpExtension('testExtThree', '>= 2.0')] + #[RequiresSetting('not_a_setting', 'Off')] + public function testAllPossibleRequirements(): void + { + } + + #[RequiresFunction('array_merge')] + public function testExistingFunction(): void + { + } + + #[RequiresMethod(ReflectionMethod::class, 'setAccessible')] + public function testExistingMethod(): void + { + } + + #[RequiresPhpExtension('spl')] + public function testExistingExtension(): void + { + } + + #[RequiresOperatingSystem('.*')] + public function testExistingOs(): void + { + } + + #[RequiresPhpunit('>= 1111111')] + public function testAlwaysSkip(): void + { + } + + #[RequiresPhp('>= 9999999')] + public function testAlwaysSkip2(): void + { + } + + #[RequiresOperatingSystem('DOESNOTEXIST')] + public function testAlwaysSkip3(): void + { + } + + #[RequiresOperatingSystemFamily('DOESNOTEXIST')] + public function testAlwaysSkip4(): void + { + } + + #[RequiresPhpExtension('spl')] + #[RequiresOperatingSystem('.*')] + public function testSpace(): void + { + } + + #[RequiresPhpExtension('testExt', '1.8.0')] + public function testSpecificExtensionVersion(): void + { + } + + #[TestDox('PHP version operator less than')] + #[RequiresPhp('< 5.4')] + public function testPHPVersionOperatorLessThan(): void + { + } + + #[TestDox('PHP version operator less than or equals')] + #[RequiresPhp('<= 5.4')] + public function testPHPVersionOperatorLessThanEquals(): void + { + } + + #[TestDox('PHP version operator greater than')] + #[RequiresPhp('> 99')] + public function testPHPVersionOperatorGreaterThan(): void + { + } + + #[TestDox('PHP version operator greater than or equals')] + #[RequiresPhp('>= 99')] + public function testPHPVersionOperatorGreaterThanEquals(): void + { + } + + #[TestDox('PHP version operator equals')] + #[RequiresPhp('= 5.4')] + public function testPHPVersionOperatorEquals(): void + { + } + + #[TestDox('PHP version operator double equals')] + #[RequiresPhp('== 5.4')] + public function testPHPVersionOperatorDoubleEquals(): void + { + } + + #[TestDox('PHP version operator bang equals')] + #[RequiresPhp('!= 99')] + public function testPHPVersionOperatorBangEquals(): void + { + } + + #[TestDox('PHP version operator not equals')] + #[RequiresPhp('<> 99')] + public function testPHPVersionOperatorNotEquals(): void + { + } + + #[TestDox('PHP version operator no space')] + #[RequiresPhp('>=99')] + public function testPHPVersionOperatorNoSpace(): void + { + } + + #[TestDox('PHPUnit version operator less than')] + #[RequiresPhpunit('< 1.0')] + public function testPHPUnitVersionOperatorLessThan(): void + { + } + + #[TestDox('PHPUnit version operator less than equals')] + #[RequiresPhpunit('<= 1.0')] + public function testPHPUnitVersionOperatorLessThanEquals(): void + { + } + + #[TestDox('PHPUnit version operator greater than')] + #[RequiresPhpunit('> 99')] + public function testPHPUnitVersionOperatorGreaterThan(): void + { + } + + #[TestDox('PHPUnit version operator greater than or equals')] + #[RequiresPhpunit('>= 99')] + public function testPHPUnitVersionOperatorGreaterThanEquals(): void + { + } + + #[TestDox('PHPUnit version operator equals')] + #[RequiresPhpunit('= 1.0')] + public function testPHPUnitVersionOperatorEquals(): void + { + } + + #[TestDox('PHPUnit version operator double equals')] + #[RequiresPhpunit('== 1.0')] + public function testPHPUnitVersionOperatorDoubleEquals(): void + { + } + + #[TestDox('PHPUnit version operator bang equals')] + #[RequiresPhpunit('!= 99')] + public function testPHPUnitVersionOperatorBangEquals(): void + { + } + + #[TestDox('PHPUnit version operator not equals')] + #[RequiresPhpunit('<> 99')] + public function testPHPUnitVersionOperatorNotEquals(): void + { + } + + #[TestDox('PHPUnit version operator no space')] + #[RequiresPhpunit('>=99')] + public function testPHPUnitVersionOperatorNoSpace(): void + { + } + + #[RequiresPhpExtension('testExtOne', '< 1.0')] + public function testExtensionVersionOperatorLessThan(): void + { + } + + #[RequiresPhpExtension('testExtOne', '<= 1.0')] + public function testExtensionVersionOperatorLessThanEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '> 99')] + public function testExtensionVersionOperatorGreaterThan(): void + { + } + + #[RequiresPhpExtension('testExtOne', '>= 99')] + public function testExtensionVersionOperatorGreaterThanEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '= 1.0')] + public function testExtensionVersionOperatorEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '== 1.0')] + public function testExtensionVersionOperatorDoubleEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '!= 99')] + public function testExtensionVersionOperatorBangEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '<> 99')] + public function testExtensionVersionOperatorNotEquals(): void + { + } + + #[RequiresPhpExtension('testExtOne', '>= 99')] + public function testExtensionVersionOperatorNoSpace(): void + { + } + + #[RequiresPhp('~1.0')] + #[RequiresPhpunit('~2.0')] + public function testVersionConstraintTildeMajor(): void + { + } + + #[RequiresPhp('^1.0')] + #[RequiresPhpunit('^2.0')] + public function testVersionConstraintCaretMajor(): void + { + } + + #[RequiresPhp('~3.4.7')] + #[RequiresPhpunit('~4.7.1')] + public function testVersionConstraintTildeMinor(): void + { + } + + #[RequiresPhp('^7.0.17')] + #[RequiresPhpunit('^4.7.1')] + public function testVersionConstraintCaretMinor(): void + { + } + + #[RequiresPhp('^5.6 || ^7.0')] + #[RequiresPhpunit('^5.0 || ^6.0')] + public function testVersionConstraintCaretOr(): void + { + } + + #[RequiresPhp('~5.6.22 || ~7.0.17')] + #[RequiresPhpunit('~5.0.5 || ~6.0.6')] + public function testVersionConstraintTildeOr(): void + { + } + + #[RequiresPhp('~5.6.22 || ^7.0')] + #[RequiresPhpunit('~5.6.22 || ^7.0')] + public function testVersionConstraintTildeOrCaret(): void + { + } + + #[RequiresPhp('^5.6 || ~7.0.17')] + #[RequiresPhpunit('^5.6 || ~7.0.17')] + public function testVersionConstraintCaretOrTilde(): void + { + } + + #[RequiresPhp('~5.6.22 || ~7.0.17')] + #[RequiresPhpunit('~5.6.22 || ~7.0.17')] + public function testVersionConstraintRegexpIgnoresWhitespace(): void + { + } + + #[RequiresSetting('display_errors', 'On')] + public function testSettingDisplayErrorsOn(): void + { + } + + #[RequiresPhpunitExtension(SomeExtension::class)] + #[RequiresPhpunitExtension(SomeOtherExtension::class)] + public function testPHPUnitExtensionRequired(): void + { + } +} diff --git a/tests/_files/RouterTest.php b/tests/_files/RouterTest.php new file mode 100644 index 00000000000..3caffc07ca8 --- /dev/null +++ b/tests/_files/RouterTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use FooBarHandler; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +final class RouterTest extends TestCase +{ + public static function routesProvider(): array + { + return [ + '/foo/bar' => [ + '/foo/bar', + FooBarHandler::class, + // ... + ], + ]; + } + + #[DataProvider('routesProvider')] + #[TestDox('Routes $url to $handler')] + public function testRoutesRequest(string $url, string $handler): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/SameClassNames/NamespaceOne/MyTest.php b/tests/_files/SameClassNames/NamespaceOne/MyTest.php new file mode 100644 index 00000000000..53dad2d0c52 --- /dev/null +++ b/tests/_files/SameClassNames/NamespaceOne/MyTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\NamespaceOne; + +use PHPUnit\Framework\TestCase; + +class MyTest extends TestCase +{ + public function test1of3(): void + { + } +} diff --git a/tests/_files/SameClassNames/NamespaceTwo/MyTest.php b/tests/_files/SameClassNames/NamespaceTwo/MyTest.php new file mode 100644 index 00000000000..e823c86e660 --- /dev/null +++ b/tests/_files/SameClassNames/NamespaceTwo/MyTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\NamespaceTwo; + +use PHPUnit\Framework\TestCase; + +class MyTest extends TestCase +{ + public function test2of3(): void + { + } + + public function test3of3(): void + { + } +} diff --git a/tests/_files/SampleArrayAccess.php b/tests/_files/SampleArrayAccess.php new file mode 100644 index 00000000000..39dccb3f7e1 --- /dev/null +++ b/tests/_files/SampleArrayAccess.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use ArrayAccess; + +final class SampleArrayAccess implements ArrayAccess +{ + private array $container; + + public function __construct() + { + $this->container = []; + } + + public function offsetSet($offset, $value): void + { + if (null === $offset) { + $this->container[] = $value; + } else { + $this->container[$offset] = $value; + } + } + + public function offsetExists($offset): bool + { + return isset($this->container[$offset]); + } + + public function offsetUnset($offset): void + { + unset($this->container[$offset]); + } + + public function offsetGet($offset): mixed + { + return $this->container[$offset] ?? null; + } +} diff --git a/tests/_files/SampleClass.php b/tests/_files/SampleClass.php new file mode 100644 index 00000000000..2c3592190ff --- /dev/null +++ b/tests/_files/SampleClass.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class SampleClass +{ + public $a; + public $b; + public $c; + + public function __construct($a, $b, $c) + { + $this->a = $a; + $this->b = $b; + $this->c = $c; + } +} diff --git a/tests/_files/SeparateProcessesTest.php b/tests/_files/SeparateProcessesTest.php new file mode 100644 index 00000000000..910a1b6a147 --- /dev/null +++ b/tests/_files/SeparateProcessesTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class SeparateProcessesTest extends TestCase +{ + public function testFoo(): void + { + $this->assertTrue(true); + + exit(0); + } + + public function testBar(): void + { + $this->assertTrue(true); + $this->assertTrue(true); + + exit(1); + } +} diff --git a/tests/_files/SmallGroupAnnotationsTest.php b/tests/_files/SmallGroupAnnotationsTest.php new file mode 100644 index 00000000000..ac32ff9b314 --- /dev/null +++ b/tests/_files/SmallGroupAnnotationsTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CoveredClass::class)] +#[UsesClass(CoveredClass::class)] +#[Group('the-group')] +#[Ticket('the-ticket')] +#[Small] +final class SmallGroupAnnotationsTest extends TestCase +{ + #[Group('another-group')] + #[Ticket('another-ticket')] + public function testOne(): void + { + } +} diff --git a/tests/_files/SmallGroupAttributesTest.php b/tests/_files/SmallGroupAttributesTest.php new file mode 100644 index 00000000000..99caa59d978 --- /dev/null +++ b/tests/_files/SmallGroupAttributesTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CoveredClass::class)] +#[UsesClass(CoveredClass::class)] +#[Group('the-group')] +#[Ticket('the-ticket')] +#[Small] +final class SmallGroupAttributesTest extends TestCase +{ + #[Group('another-group')] + #[Ticket('another-ticket')] + public function testOne(): void + { + } +} diff --git a/tests/_files/StopOnErrorTestSuite.php b/tests/_files/StopOnErrorTestSuite.php new file mode 100644 index 00000000000..f40e0535b4a --- /dev/null +++ b/tests/_files/StopOnErrorTestSuite.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Error; +use PHPUnit\Framework\TestCase; + +final class StopOnErrorTestSuite extends TestCase +{ + public function testIncomplete(): void + { + $this->markTestIncomplete(); + } + + public function testWithError(): void + { + $this->assertTrue(true); + + throw new Error('StopOnErrorTestSuite_error'); + } + + public function testThatIsNeverReached(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/StopsOnWarningTest.php b/tests/_files/StopsOnWarningTest.php new file mode 100644 index 00000000000..e4d6a24077f --- /dev/null +++ b/tests/_files/StopsOnWarningTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class StopsOnWarningTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/Struct.php b/tests/_files/Struct.php new file mode 100644 index 00000000000..aa831b919d3 --- /dev/null +++ b/tests/_files/Struct.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class Struct +{ + public $var; + + public function __construct($var) + { + $this->var = $var; + } +} diff --git a/tests/_files/Success.php b/tests/_files/Success.php new file mode 100644 index 00000000000..41e717eceda --- /dev/null +++ b/tests/_files/Success.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Success extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/TemplateMethodsTest.php b/tests/_files/TemplateMethodsTest.php new file mode 100644 index 00000000000..5a55140bcb8 --- /dev/null +++ b/tests/_files/TemplateMethodsTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; +use Throwable; + +final class TemplateMethodsTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + print __METHOD__ . "\n"; + } + + public static function tearDownAfterClass(): void + { + print __METHOD__ . "\n"; + } + + protected function setUp(): void + { + print __METHOD__ . "\n"; + } + + protected function assertPreConditions(): void + { + print __METHOD__ . "\n"; + } + + protected function assertPostConditions(): void + { + print __METHOD__ . "\n"; + } + + protected function tearDown(): void + { + print __METHOD__ . "\n"; + } + + public function testOne(): void + { + print __METHOD__ . "\n"; + $this->assertTrue(true); + } + + public function testTwo(): void + { + print __METHOD__ . "\n"; + $this->assertTrue(false); + } + + protected function onNotSuccessfulTest(Throwable $t): void + { + print __METHOD__ . "\n"; + + throw $t; + } +} diff --git a/tests/_files/TestCaseTest.php b/tests/_files/TestCaseTest.php new file mode 100644 index 00000000000..adcb7bb84a5 --- /dev/null +++ b/tests/_files/TestCaseTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +final class TestCaseTest extends TestCase +{ + public function testOne(): void + { + } + + #[Test] + public function two(): void + { + } + + public function three(): void + { + } + + private function four(): void + { + } +} diff --git a/tests/_files/TestCaseWithExceptionInHook.php b/tests/_files/TestCaseWithExceptionInHook.php new file mode 100644 index 00000000000..274301166b8 --- /dev/null +++ b/tests/_files/TestCaseWithExceptionInHook.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class TestCaseWithExceptionInHook extends TestCase +{ + /** + * @throws Exception + */ + public static function setUpBeforeClass(): void + { + throw new Exception; + } + + public function testTrue(): void + { + $this->assertTrue(true); + } + + public function testFalse(): void + { + $this->assertFalse(false); + } +} diff --git a/tests/_files/TestDoxAttributeOnTestClassTest.php b/tests/_files/TestDoxAttributeOnTestClassTest.php new file mode 100644 index 00000000000..c80a893998f --- /dev/null +++ b/tests/_files/TestDoxAttributeOnTestClassTest.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Custom Title')] +final class TestDoxAttributeOnTestClassTest extends TestCase +{ +} diff --git a/tests/_files/TestDoxTest.php b/tests/_files/TestDoxTest.php new file mode 100644 index 00000000000..a5ab4a1c471 --- /dev/null +++ b/tests/_files/TestDoxTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class TestDoxTest extends TestCase +{ + public static function formatter(DateTimeImmutable $date): string + { + return 'This is a custom description: ' . $date->format('Y-m-d'); + } + + public function testOne(): void + { + } + + public function testTwo(): void + { + } + + #[TestDox('This is a custom test description')] + public function testThree(): void + { + } + + #[TestDox('This is a custom test description with placeholders $a $b $f $i $s $o $stdClass $enum $backedEnum $n $empty $default')] + public function testFour(array $a, bool $b, float $f, int $i, string $s, object $o, object $stdClass, $enum, $backedEnum, $n, string $empty, string $default = 'default'): void + { + } + + #[TestDoxFormatter('formatter')] + public function testFive(DateTimeImmutable $date): void + { + } +} diff --git a/tests/_files/TestError.php b/tests/_files/TestError.php new file mode 100644 index 00000000000..415a0b69a67 --- /dev/null +++ b/tests/_files/TestError.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class TestError extends TestCase +{ + public function testOne(): void + { + throw new Exception; + } +} diff --git a/tests/_files/TestGeneratorMaker.php b/tests/_files/TestGeneratorMaker.php new file mode 100644 index 00000000000..1fbf8a4a361 --- /dev/null +++ b/tests/_files/TestGeneratorMaker.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class TestGeneratorMaker +{ + public function create($array = []) + { + foreach ($array as $key => $value) { + yield $key => $value; + } + } +} diff --git a/tests/_files/TestIncomplete.php b/tests/_files/TestIncomplete.php new file mode 100644 index 00000000000..cffe5587fab --- /dev/null +++ b/tests/_files/TestIncomplete.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class TestIncomplete extends TestCase +{ + public function testOne(): void + { + $this->markTestIncomplete('Incomplete test'); + } +} diff --git a/tests/_files/TestIterator.php b/tests/_files/TestIterator.php new file mode 100644 index 00000000000..f74de3d1cfd --- /dev/null +++ b/tests/_files/TestIterator.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function count; +use Iterator; + +final class TestIterator implements Iterator +{ + private array $array; + private int $position = 0; + + public function __construct(array $array = []) + { + $this->array = $array; + } + + public function rewind(): void + { + $this->position = 0; + } + + public function valid(): bool + { + return $this->position < count($this->array); + } + + public function key(): int|string + { + return $this->position; + } + + public function current(): mixed + { + return $this->array[$this->position]; + } + + public function next(): void + { + $this->position++; + } +} diff --git a/tests/_files/TestIterator2.php b/tests/_files/TestIterator2.php new file mode 100644 index 00000000000..cb225d5995b --- /dev/null +++ b/tests/_files/TestIterator2.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function current; +use function key; +use function next; +use function reset; +use Iterator; + +final class TestIterator2 implements Iterator +{ + private array $data; + + public function __construct(array $array) + { + $this->data = $array; + } + + public function current(): mixed + { + return current($this->data); + } + + public function next(): void + { + next($this->data); + } + + public function key(): null|int|string + { + return key($this->data); + } + + public function valid(): bool + { + return key($this->data) !== null; + } + + public function rewind(): void + { + reset($this->data); + } +} diff --git a/tests/_files/TestIteratorAggregate.php b/tests/_files/TestIteratorAggregate.php new file mode 100644 index 00000000000..e13d7ade16d --- /dev/null +++ b/tests/_files/TestIteratorAggregate.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use IteratorAggregate; +use Traversable; + +final class TestIteratorAggregate implements IteratorAggregate +{ + private Traversable $traversable; + + public function __construct(Traversable $traversable) + { + $this->traversable = $traversable; + } + + public function getIterator(): Traversable + { + return $this->traversable; + } +} diff --git a/tests/_files/TestIteratorAggregate2.php b/tests/_files/TestIteratorAggregate2.php new file mode 100644 index 00000000000..9a14ec6cb5c --- /dev/null +++ b/tests/_files/TestIteratorAggregate2.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use IteratorAggregate; +use Traversable; + +final class TestIteratorAggregate2 implements IteratorAggregate +{ + private Traversable $traversable; + + public function __construct(Traversable $traversable) + { + $this->traversable = $traversable; + } + + public function getIterator(): Traversable + { + return $this->traversable; + } +} diff --git a/tests/_files/TestWithAttributeDataProviderTest.php b/tests/_files/TestWithAttributeDataProviderTest.php new file mode 100644 index 00000000000..64c7fd4c0cf --- /dev/null +++ b/tests/_files/TestWithAttributeDataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\TestCase; + +final class TestWithAttributeDataProviderTest extends TestCase +{ + #[TestWith(['a', 'b'], 'foo')] + #[TestWith(['c', 'd'], 'bar')] + #[TestWith(['e', 'f'])] + #[TestWith(['g', 'h'])] + public function testWithAttribute($one, $two): void + { + } + + #[TestWith(['a', 'b'], 'foo')] + #[TestWith(['c', 'd'], 'foo')] + public function testWithDuplicateName($one, $two): void + { + } +} diff --git a/tests/_files/TestWithClassLevelIsolationAttributes.php b/tests/_files/TestWithClassLevelIsolationAttributes.php new file mode 100644 index 00000000000..40a6314f12c --- /dev/null +++ b/tests/_files/TestWithClassLevelIsolationAttributes.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestBuilder; + +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[BackupGlobals(true)] +#[BackupStaticProperties(true)] +#[RunTestsInSeparateProcesses] +final class TestWithClassLevelIsolationAttributes extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/TestWithDataProvider.php b/tests/_files/TestWithDataProvider.php new file mode 100644 index 00000000000..f0c2fa7ff23 --- /dev/null +++ b/tests/_files/TestWithDataProvider.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestBuilder; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class TestWithDataProvider extends TestCase +{ + public static function provider(): array + { + return [[0]]; + } + + #[DataProvider('provider')] + public function testOne(int $zero): void + { + } +} diff --git a/tests/_files/TestWithDifferentNames.php b/tests/_files/TestWithDifferentNames.php new file mode 100644 index 00000000000..2f03fadf5f1 --- /dev/null +++ b/tests/_files/TestWithDifferentNames.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class TestWithDifferentNames extends TestCase +{ + public function testWithName(): void + { + } +} diff --git a/tests/_files/TestWithHookMethodsPrioritizedTest.php b/tests/_files/TestWithHookMethodsPrioritizedTest.php new file mode 100644 index 00000000000..96b0afe9c24 --- /dev/null +++ b/tests/_files/TestWithHookMethodsPrioritizedTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\TestCase; + +final class TestWithHookMethodsPrioritizedTest extends TestCase +{ + #[BeforeClass(priority: 1)] + public static function beforeFirstTest(): void + { + } + + #[AfterClass(priority: 6)] + public static function afterLastTest(): void + { + } + + #[Before(priority: 2)] + protected function beforeEachTest(): void + { + } + + #[PreCondition(priority: 3)] + protected function preConditions(): void + { + } + + #[PostCondition(priority: 4)] + protected function postConditions(): void + { + } + + #[After(priority: 5)] + protected function afterEachTest(): void + { + } +} diff --git a/tests/_files/TestWithHookMethodsTest.php b/tests/_files/TestWithHookMethodsTest.php new file mode 100644 index 00000000000..d7f15a8548a --- /dev/null +++ b/tests/_files/TestWithHookMethodsTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\TestCase; + +final class TestWithHookMethodsTest extends TestCase +{ + #[BeforeClass] + public static function beforeFirstTestWithAttribute(): void + { + } + + #[AfterClass] + public static function afterLastTestWithAttribute(): void + { + } + + #[Before] + protected function beforeEachTestWithAttribute(): void + { + } + + #[After] + protected function afterEachTestWithAttribute(): void + { + } + + #[PreCondition] + protected function preConditionsWithAttribute(): void + { + } + + #[PostCondition] + protected function postConditionsWithAttribute(): void + { + } +} diff --git a/tests/_files/TestWithMethodLevelIsolationAttributes.php b/tests/_files/TestWithMethodLevelIsolationAttributes.php new file mode 100644 index 00000000000..2687e906e49 --- /dev/null +++ b/tests/_files/TestWithMethodLevelIsolationAttributes.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestBuilder; + +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class TestWithMethodLevelIsolationAttributes extends TestCase +{ + #[BackupGlobals(true)] + #[BackupStaticProperties(true)] + #[RunInSeparateProcess] + public function testOne(): void + { + } +} diff --git a/tests/_files/TestWithoutHookMethodsTest.php b/tests/_files/TestWithoutHookMethodsTest.php new file mode 100644 index 00000000000..79cc6b39741 --- /dev/null +++ b/tests/_files/TestWithoutHookMethodsTest.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class TestWithoutHookMethodsTest extends TestCase +{ +} diff --git a/tests/_files/TestWithoutIsolationAttributes.php b/tests/_files/TestWithoutIsolationAttributes.php new file mode 100644 index 00000000000..c6d1498be45 --- /dev/null +++ b/tests/_files/TestWithoutIsolationAttributes.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestBuilder; + +use PHPUnit\Framework\TestCase; + +final class TestWithoutIsolationAttributes extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/_files/ThrowExceptionTestCase.php b/tests/_files/ThrowExceptionTestCase.php new file mode 100644 index 00000000000..0835a0b31e4 --- /dev/null +++ b/tests/_files/ThrowExceptionTestCase.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; +use RuntimeException; + +final class ThrowExceptionTestCase extends TestCase +{ + public function test(): void + { + throw new RuntimeException('A runtime error occurred'); + } + + public function testWithExpectExceptionObject(): void + { + throw new RuntimeException( + 'Cannot compute at this time.', + 9000, + ); + } +} diff --git a/tests/_files/ThrowNoExceptionTestCase.php b/tests/_files/ThrowNoExceptionTestCase.php new file mode 100644 index 00000000000..beb5605ba9d --- /dev/null +++ b/tests/_files/ThrowNoExceptionTestCase.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class ThrowNoExceptionTestCase extends TestCase +{ + public function test(): void + { + } +} diff --git a/tests/_files/VariousIterableDataProviderTest.php b/tests/_files/VariousIterableDataProviderTest.php new file mode 100644 index 00000000000..cb518069911 --- /dev/null +++ b/tests/_files/VariousIterableDataProviderTest.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Generator; +use PHPUnit\Framework\Attributes\DataProvider; + +final class VariousIterableDataProviderTest extends AbstractVariousIterableDataProviderTest +{ + public static function asArrayStaticProvider(): array + { + return [ + ['A'], + ['B'], + ['C'], + ]; + } + + public static function asIteratorStaticProvider(): Generator + { + yield ['D']; + + yield ['E']; + + yield ['F']; + } + + public static function asTraversableStaticProvider(): WrapperIteratorAggregate + { + return new WrapperIteratorAggregate([ + ['G'], + ['H'], + ['I'], + ]); + } + + public static function asArrayProvider(): array + { + return [ + ['S'], + ['T'], + ['U'], + ]; + } + + public static function asIteratorProvider(): Generator + { + yield ['V']; + + yield ['W']; + + yield ['X']; + } + + public static function asTraversableProvider(): WrapperIteratorAggregate + { + return new WrapperIteratorAggregate([ + ['Y'], + ['Z'], + ['P'], + ]); + } + + #[DataProvider('asArrayStaticProvider')] + #[DataProvider('asIteratorStaticProvider')] + #[DataProvider('asTraversableStaticProvider')] + public function testStatic(string $x): void + { + } + + #[DataProvider('asArrayProvider')] + #[DataProvider('asIteratorProvider')] + #[DataProvider('asTraversableProvider')] + public function testNonStatic(string $x): void + { + } + + #[DataProvider('asArrayProviderInParent')] + #[DataProvider('asIteratorProviderInParent')] + #[DataProvider('asTraversableProviderInParent')] + public function testFromParent(string $x): void + { + } +} diff --git a/tests/_files/WrapperIteratorAggregate.php b/tests/_files/WrapperIteratorAggregate.php new file mode 100644 index 00000000000..9bb3666bbd3 --- /dev/null +++ b/tests/_files/WrapperIteratorAggregate.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Generator; +use IteratorAggregate; + +final class WrapperIteratorAggregate implements IteratorAggregate +{ + private iterable $baseCollection; + + public function __construct(iterable $baseCollection) + { + $this->baseCollection = $baseCollection; + } + + public function getIterator(): Generator + { + foreach ($this->baseCollection as $k => $v) { + yield $k => $v; + } + } +} diff --git a/tests/_files/XmlConfigurationMigration/input-9.2.xml b/tests/_files/XmlConfigurationMigration/input-9.2.xml new file mode 100644 index 00000000000..5ca77be85d2 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-9.2.xml @@ -0,0 +1,38 @@ + + + + + + src + + + src/generated + src/autoload.php + + + src/other + src/some.php + + + + + + + + + + + + + + + + + + + diff --git a/tests/_files/XmlConfigurationMigration/input-9.5.xml b/tests/_files/XmlConfigurationMigration/input-9.5.xml new file mode 100644 index 00000000000..4b65160d283 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-9.5.xml @@ -0,0 +1,69 @@ + + + + + + src + + + + + + + + + Sebastian + + + 22 + April + 19.78 + + + MyTestFile.php + MyRelativePath + true + + + + + + 42 + false + + + + + + + + + + + + bar + + + foo + + + diff --git a/tests/_files/XmlConfigurationMigration/input-issue-5859.xml b/tests/_files/XmlConfigurationMigration/input-issue-5859.xml new file mode 100644 index 00000000000..ee91318f785 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-issue-5859.xml @@ -0,0 +1,5 @@ + + + + diff --git a/tests/_files/XmlConfigurationMigration/input-issue-6087.xml b/tests/_files/XmlConfigurationMigration/input-issue-6087.xml new file mode 100644 index 00000000000..8ba9d4b4814 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-issue-6087.xml @@ -0,0 +1,11 @@ + + + + + tests + + + diff --git a/tests/_files/XmlConfigurationMigration/input-no-schema-location.xml b/tests/_files/XmlConfigurationMigration/input-no-schema-location.xml new file mode 100644 index 00000000000..a8dcad340fd --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-no-schema-location.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_files/XmlConfigurationMigration/input-relative-schema-path.xml b/tests/_files/XmlConfigurationMigration/input-relative-schema-path.xml new file mode 100644 index 00000000000..2bd593509cf --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/input-relative-schema-path.xml @@ -0,0 +1,5 @@ + + + + diff --git a/tests/_files/XmlConfigurationMigration/output-9.2.xml b/tests/_files/XmlConfigurationMigration/output-9.2.xml new file mode 100644 index 00000000000..935675cdd20 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-9.2.xml @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + src + + + + src/generated + src/autoload.php + src/other + src/some.php + + + diff --git a/tests/_files/XmlConfigurationMigration/output-9.5.xml b/tests/_files/XmlConfigurationMigration/output-9.5.xml new file mode 100644 index 00000000000..b3f5451fb61 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-9.5.xml @@ -0,0 +1,17 @@ + + + + + + + + src + + + + diff --git a/tests/_files/XmlConfigurationMigration/output-issue-5859.xml b/tests/_files/XmlConfigurationMigration/output-issue-5859.xml new file mode 100644 index 00000000000..d64ecdd3163 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-issue-5859.xml @@ -0,0 +1,5 @@ + + + + diff --git a/tests/_files/XmlConfigurationMigration/output-issue-6087.xml b/tests/_files/XmlConfigurationMigration/output-issue-6087.xml new file mode 100644 index 00000000000..3f026e8929a --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-issue-6087.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/_files/XmlConfigurationMigration/output-no-schema-location.xml b/tests/_files/XmlConfigurationMigration/output-no-schema-location.xml new file mode 100644 index 00000000000..9a3ead90b74 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-no-schema-location.xml @@ -0,0 +1,4 @@ + + + + diff --git a/tests/_files/XmlConfigurationMigration/output-relative-schema-path.xml b/tests/_files/XmlConfigurationMigration/output-relative-schema-path.xml new file mode 100644 index 00000000000..31fa3f9c8a6 --- /dev/null +++ b/tests/_files/XmlConfigurationMigration/output-relative-schema-path.xml @@ -0,0 +1,5 @@ + + + + diff --git a/tests/_files/abstract/with-test-suffix/AbstractTest.php b/tests/_files/abstract/with-test-suffix/AbstractTest.php new file mode 100644 index 00000000000..d45ed8014c6 --- /dev/null +++ b/tests/_files/abstract/with-test-suffix/AbstractTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/abstract/with-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithTestSuffixTest.php b/tests/_files/abstract/with-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithTestSuffixTest.php new file mode 100644 index 00000000000..f7cf69ad134 --- /dev/null +++ b/tests/_files/abstract/with-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithTestSuffixTest.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class ConcreteTestClassExtendingAbstractTestClassWithTestSuffixTest extends AbstractTest +{ +} diff --git a/tests/_files/abstract/without-test-suffix/AbstractTestCase.php b/tests/_files/abstract/without-test-suffix/AbstractTestCase.php new file mode 100644 index 00000000000..24967dfea54 --- /dev/null +++ b/tests/_files/abstract/without-test-suffix/AbstractTestCase.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractTestCase extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/abstract/without-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest.php b/tests/_files/abstract/without-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest.php new file mode 100644 index 00000000000..528d679382f --- /dev/null +++ b/tests/_files/abstract/without-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest extends AbstractTestCase +{ +} diff --git a/tests/_files/actualFileFormat.txt b/tests/_files/actualFileFormat.txt new file mode 100644 index 00000000000..ba578e48b18 --- /dev/null +++ b/tests/_files/actualFileFormat.txt @@ -0,0 +1 @@ +BAR diff --git a/tests/_files/bar.txt b/tests/_files/bar.txt new file mode 100644 index 00000000000..351f9261cd1 --- /dev/null +++ b/tests/_files/bar.txt @@ -0,0 +1 @@ +Voulez-vous un café? diff --git a/Tests/_files/bar.xml b/tests/_files/bar.xml similarity index 100% rename from Tests/_files/bar.xml rename to tests/_files/bar.xml diff --git a/tests/_files/baseline/FileWithIssues.php b/tests/_files/baseline/FileWithIssues.php new file mode 100644 index 00000000000..13bdbb6af19 --- /dev/null +++ b/tests/_files/baseline/FileWithIssues.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +$a = $b; +$b = $c; diff --git a/tests/_files/baseline/expected.xml b/tests/_files/baseline/expected.xml new file mode 100644 index 00000000000..f41e43f5995 --- /dev/null +++ b/tests/_files/baseline/expected.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/tests/_files/configuration-issue-6340.xml b/tests/_files/configuration-issue-6340.xml new file mode 100644 index 00000000000..6d6964b6aa4 --- /dev/null +++ b/tests/_files/configuration-issue-6340.xml @@ -0,0 +1,12 @@ + + + diff --git a/tests/_files/configuration.colors.empty.xml b/tests/_files/configuration.colors.empty.xml new file mode 100644 index 00000000000..5f9e0556543 --- /dev/null +++ b/tests/_files/configuration.colors.empty.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/configuration.colors.false.xml b/tests/_files/configuration.colors.false.xml new file mode 100644 index 00000000000..dcd4aa47e0c --- /dev/null +++ b/tests/_files/configuration.colors.false.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/configuration.colors.invalid.xml b/tests/_files/configuration.colors.invalid.xml new file mode 100644 index 00000000000..c5bd6990e4d --- /dev/null +++ b/tests/_files/configuration.colors.invalid.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/configuration.colors.true.xml b/tests/_files/configuration.colors.true.xml new file mode 100644 index 00000000000..1efe413250d --- /dev/null +++ b/tests/_files/configuration.colors.true.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/configuration.columns.default.xml b/tests/_files/configuration.columns.default.xml new file mode 100644 index 00000000000..c2cb278736c --- /dev/null +++ b/tests/_files/configuration.columns.default.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/configuration.defaulttestsuite.xml b/tests/_files/configuration.defaulttestsuite.xml new file mode 100644 index 00000000000..cc17002f322 --- /dev/null +++ b/tests/_files/configuration.defaulttestsuite.xml @@ -0,0 +1,10 @@ + + + + ../_files/DummyFooTest.php + + + ../_files/DummyBarTest.php + + + diff --git a/tests/_files/configuration.depends-on-class.xml b/tests/_files/configuration.depends-on-class.xml new file mode 100644 index 00000000000..3eca540590c --- /dev/null +++ b/tests/_files/configuration.depends-on-class.xml @@ -0,0 +1,11 @@ + + + + ../../tests/_files/DependencyOnClassTest.php + ../../tests/_files/dependencies/DependencyFailureTest.php + + + ../../tests/_files/dependencies/DependencySuccessTest.php + + + diff --git a/tests/_files/configuration.testsuite_no_name.xml b/tests/_files/configuration.testsuite_no_name.xml new file mode 100644 index 00000000000..34b327d3ef6 --- /dev/null +++ b/tests/_files/configuration.testsuite_no_name.xml @@ -0,0 +1,6 @@ + + + + tests + + diff --git a/tests/_files/configuration.xml b/tests/_files/configuration.xml new file mode 100644 index 00000000000..f29010b7b0e --- /dev/null +++ b/tests/_files/configuration.xml @@ -0,0 +1,87 @@ + + + + + /path/to/files + /path/to/MyTest.php + + + + + + name + + + name + + + + + + name + + + name + + + + + + + + + + + + . + /path/to/lib + + + + + + + + + + + + + + + + + diff --git a/tests/_files/configuration_codecoverage.xml b/tests/_files/configuration_codecoverage.xml new file mode 100644 index 00000000000..55f1e5653e5 --- /dev/null +++ b/tests/_files/configuration_codecoverage.xml @@ -0,0 +1,38 @@ + + + + + /path/to/files + /path/to/file + + /path/to/file + + + + + /path/to/files + /path/to/file + + + + PHPUnit\TestFixture\DeprecationTrigger\trigger_deprecation + PHPUnit\TestFixture\DeprecationTrigger\DeprecationTrigger::triggerDeprecation + + + + + + + + + + + + + + + + diff --git a/tests/_files/configuration_empty.xml b/tests/_files/configuration_empty.xml new file mode 100644 index 00000000000..f30eb62cf5f --- /dev/null +++ b/tests/_files/configuration_empty.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/_files/configuration_logging.xml b/tests/_files/configuration_logging.xml new file mode 100644 index 00000000000..a66e7f22b06 --- /dev/null +++ b/tests/_files/configuration_logging.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/tests/_files/configuration_stop_on_defect.xml b/tests/_files/configuration_stop_on_defect.xml new file mode 100644 index 00000000000..8cfdf60b198 --- /dev/null +++ b/tests/_files/configuration_stop_on_defect.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/_files/configuration_stop_on_error.xml b/tests/_files/configuration_stop_on_error.xml new file mode 100644 index 00000000000..77e440eb06e --- /dev/null +++ b/tests/_files/configuration_stop_on_error.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/_files/configuration_stop_on_incomplete.xml b/tests/_files/configuration_stop_on_incomplete.xml new file mode 100644 index 00000000000..08a63900b75 --- /dev/null +++ b/tests/_files/configuration_stop_on_incomplete.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/_files/configuration_stop_on_warning.xml b/tests/_files/configuration_stop_on_warning.xml new file mode 100644 index 00000000000..8bcd06a1859 --- /dev/null +++ b/tests/_files/configuration_stop_on_warning.xml @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/tests/_files/configuration_testdox.xml b/tests/_files/configuration_testdox.xml new file mode 100644 index 00000000000..f01f3ca8ec2 --- /dev/null +++ b/tests/_files/configuration_testdox.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/_files/configuration_testdox_printerClass.xml b/tests/_files/configuration_testdox_printerClass.xml new file mode 100644 index 00000000000..363422bfe07 --- /dev/null +++ b/tests/_files/configuration_testdox_printerClass.xml @@ -0,0 +1,2 @@ + + diff --git a/tests/_files/configuration_testsuite.xml b/tests/_files/configuration_testsuite.xml new file mode 100644 index 00000000000..54fe26c1cc6 --- /dev/null +++ b/tests/_files/configuration_testsuite.xml @@ -0,0 +1,7 @@ + + + + tests/first + + diff --git a/tests/_files/configuration_testsuites.xml b/tests/_files/configuration_testsuites.xml new file mode 100644 index 00000000000..b7ce961b927 --- /dev/null +++ b/tests/_files/configuration_testsuites.xml @@ -0,0 +1,15 @@ + + + + + tests/first + + + + tests/second + tests/file.php + tests/second/_files + + + diff --git a/tests/_files/configuration_xinclude.xml b/tests/_files/configuration_xinclude.xml new file mode 100644 index 00000000000..8e1b12d71e6 --- /dev/null +++ b/tests/_files/configuration_xinclude.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + . + /path/to/lib + + + + + + + + + + + + + + + + + + diff --git a/tests/_files/delete_directory.php b/tests/_files/delete_directory.php new file mode 100644 index 00000000000..f8776bbb8a8 --- /dev/null +++ b/tests/_files/delete_directory.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +function delete_directory(string $directory): void +{ + if (\is_file($directory)) { + @\unlink($directory); + + return; + } + + if (!\is_dir($directory)) { + return; + } + + foreach (\glob(\rtrim($directory, '/') . '/*') as $path) { + delete_directory($path); + } + + @\rmdir($directory); +} diff --git a/tests/_files/dependencies/DependencyFailureTest.php b/tests/_files/dependencies/DependencyFailureTest.php new file mode 100644 index 00000000000..06a86e6c2d1 --- /dev/null +++ b/tests/_files/dependencies/DependencyFailureTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsUsingShallowClone; +use PHPUnit\Framework\TestCase; + +class DependencyFailureTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(false); + } + + #[Depends('testOne')] + public function testTwo(): void + { + $this->assertTrue(true); + } + + #[Depends('testTwo')] + public function testThree(): void + { + $this->assertTrue(true); + } + + #[DependsUsingShallowClone('testOne')] + public function testFour(): void + { + $this->assertTrue(true); + } + + #[Depends('doesNotExist')] + public function testHandlesDependencyOnTestMethodThatDoesNotExist(): void + { + $this->assertTrue(true); + } + + #[Depends('')] + public function testHandlesDependencyOnTestMethodWithEmptyName(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/dependencies/DependencySuccessTest.php b/tests/_files/dependencies/DependencySuccessTest.php new file mode 100644 index 00000000000..cc9cd119924 --- /dev/null +++ b/tests/_files/dependencies/DependencySuccessTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\TestCase; + +class DependencySuccessTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Depends('testOne')] + public function testTwo(): void + { + $this->assertTrue(true); + } + + #[DependsExternal(self::class, 'testTwo')] + public function testThree(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/_files/deprecation-trigger/DeprecationTrigger.php b/tests/_files/deprecation-trigger/DeprecationTrigger.php new file mode 100644 index 00000000000..d66323d11c6 --- /dev/null +++ b/tests/_files/deprecation-trigger/DeprecationTrigger.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DeprecationTrigger; + +final class DeprecationTrigger +{ + public function triggerDeprecation(): void + { + } +} diff --git a/tests/_files/deprecation-trigger/trigger_deprecation.php b/tests/_files/deprecation-trigger/trigger_deprecation.php new file mode 100644 index 00000000000..0979dc3976f --- /dev/null +++ b/tests/_files/deprecation-trigger/trigger_deprecation.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DeprecationTrigger; + +function trigger_deprecation(): void +{ +} diff --git a/tests/_files/empty.xml b/tests/_files/empty.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Tests/_files/expectedFileFormat.txt b/tests/_files/expectedFileFormat.txt similarity index 100% rename from Tests/_files/expectedFileFormat.txt rename to tests/_files/expectedFileFormat.txt diff --git a/tests/_files/failure.phpt b/tests/_files/failure.phpt new file mode 100644 index 00000000000..2d76d87f7ab --- /dev/null +++ b/tests/_files/failure.phpt @@ -0,0 +1,7 @@ +--TEST-- +failure +--FILE-- + diff --git a/tests/_files/invalid-configuration.txt b/tests/_files/invalid-configuration.txt new file mode 100644 index 00000000000..5ad2e3eaded --- /dev/null +++ b/tests/_files/invalid-configuration.txt @@ -0,0 +1,9 @@ + + Line 10: + - Element 'phpunit', attribute 'forceCoversAnnotation': The attribute 'forceCoversAnnotation' is not allowed. + - Element 'phpunit', attribute 'beStrictAboutCoversAnnotation': The attribute 'beStrictAboutCoversAnnotation' is not allowed. + - Element 'phpunit', attribute 'beStrictAboutTodoAnnotatedTests': The attribute 'beStrictAboutTodoAnnotatedTests' is not allowed. + - Element 'phpunit', attribute 'verbose': The attribute 'verbose' is not allowed. + + Line 17: + - Element 'filter': This element is not expected. diff --git a/tests/_files/invalid.xml b/tests/_files/invalid.xml new file mode 100644 index 00000000000..c8e2165a0e9 --- /dev/null +++ b/tests/_files/invalid.xml @@ -0,0 +1 @@ + diff --git a/tests/_files/mock-object/AbstractClass.php b/tests/_files/mock-object/AbstractClass.php new file mode 100644 index 00000000000..b5d8f899e62 --- /dev/null +++ b/tests/_files/mock-object/AbstractClass.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +abstract class AbstractClass +{ + public function doSomething(): bool + { + return $this->doSomethingElse(); + } + + abstract public function doSomethingElse(): bool; +} diff --git a/tests/_files/mock-object/AnInterface.php b/tests/_files/mock-object/AnInterface.php new file mode 100644 index 00000000000..59d52d323da --- /dev/null +++ b/tests/_files/mock-object/AnInterface.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface AnInterface +{ + public function doSomething(): bool; +} diff --git a/tests/_files/mock-object/AnInterfaceForIssue5593.php b/tests/_files/mock-object/AnInterfaceForIssue5593.php new file mode 100644 index 00000000000..e084154730c --- /dev/null +++ b/tests/_files/mock-object/AnInterfaceForIssue5593.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface AnInterfaceForIssue5593 +{ + public function doSomething(): AnotherInterfaceForIssue5593; +} diff --git a/tests/_files/mock-object/AnotherInterface.php b/tests/_files/mock-object/AnotherInterface.php new file mode 100644 index 00000000000..4710dd09563 --- /dev/null +++ b/tests/_files/mock-object/AnotherInterface.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface AnotherInterface +{ + public function doSomethingElse(); +} diff --git a/tests/_files/mock-object/AnotherInterfaceForIssue5593.php b/tests/_files/mock-object/AnotherInterfaceForIssue5593.php new file mode 100644 index 00000000000..81f695a029f --- /dev/null +++ b/tests/_files/mock-object/AnotherInterfaceForIssue5593.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface AnotherInterfaceForIssue5593 +{ + public function doSomethingElse(): static; +} diff --git a/tests/_files/mock-object/AnotherInterfaceThatDoesSomething.php b/tests/_files/mock-object/AnotherInterfaceThatDoesSomething.php new file mode 100644 index 00000000000..ef3f767f70e --- /dev/null +++ b/tests/_files/mock-object/AnotherInterfaceThatDoesSomething.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface AnotherInterfaceThatDoesSomething +{ + public function doSomething(); +} diff --git a/tests/_files/mock-object/Enumeration.php b/tests/_files/mock-object/Enumeration.php new file mode 100644 index 00000000000..3ce989776a4 --- /dev/null +++ b/tests/_files/mock-object/Enumeration.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +enum Enumeration +{ +} diff --git a/tests/_files/mock-object/ExampleTrait.php b/tests/_files/mock-object/ExampleTrait.php new file mode 100644 index 00000000000..36f5f1de0cc --- /dev/null +++ b/tests/_files/mock-object/ExampleTrait.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +trait ExampleTrait +{ + public function ohHai() + { + return __FUNCTION__; + } +} diff --git a/tests/_files/mock-object/ExtendableClass.php b/tests/_files/mock-object/ExtendableClass.php new file mode 100644 index 00000000000..dbe29c1294e --- /dev/null +++ b/tests/_files/mock-object/ExtendableClass.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClass +{ + public bool $constructorCalled = false; + + public function __construct() + { + $this->constructorCalled = true; + } + + public function __destruct() + { + } + + public function doSomething(): bool + { + return $this->doSomethingElse(); + } + + public function doSomethingElse(): bool + { + return false; + } + + final public function finalMethod(): void + { + } + + private function privateMethod(): void + { + } +} diff --git a/tests/_files/mock-object/ExtendableClassCallingMethodInConstructor.php b/tests/_files/mock-object/ExtendableClassCallingMethodInConstructor.php new file mode 100644 index 00000000000..dc380ddd5f9 --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassCallingMethodInConstructor.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClassCallingMethodInConstructor +{ + public function __construct() + { + $this->reset(); + } + + public function reset(): void + { + } + + public function second(): void + { + $this->reset(); + } +} diff --git a/tests/_files/mock-object/ExtendableClassCallingMethodInDestructor.php b/tests/_files/mock-object/ExtendableClassCallingMethodInDestructor.php new file mode 100644 index 00000000000..8141c83345b --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassCallingMethodInDestructor.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClassCallingMethodInDestructor +{ + public function __destruct() + { + $this->doSomethingElse(); + } + + public function doSomething(): static + { + return $this; + } + + public function doSomethingElse(): void + { + } +} diff --git a/tests/_files/mock-object/ExtendableClassWithCloneMethod.php b/tests/_files/mock-object/ExtendableClassWithCloneMethod.php new file mode 100644 index 00000000000..54f4c9a2cf6 --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassWithCloneMethod.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +use Exception; + +class ExtendableClassWithCloneMethod +{ + /** + * @throws Exception + */ + public function __clone(): void + { + throw new Exception(__METHOD__); + } + + public function doSomething(): bool + { + return true; + } +} diff --git a/tests/_files/mock-object/ExtendableClassWithConstructorArguments.php b/tests/_files/mock-object/ExtendableClassWithConstructorArguments.php new file mode 100644 index 00000000000..996151caa75 --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassWithConstructorArguments.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClassWithConstructorArguments +{ + private string $value; + + public function __construct(string $value) + { + $this->value = $value; + } + + public function value(): string + { + return $this->value; + } +} diff --git a/tests/_files/mock-object/ExtendableClassWithPropertyWithGetHook.php b/tests/_files/mock-object/ExtendableClassWithPropertyWithGetHook.php new file mode 100644 index 00000000000..dc5051f8d07 --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassWithPropertyWithGetHook.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClassWithPropertyWithGetHook +{ + public string $property { + get { + return 'value'; + } + } +} diff --git a/tests/_files/mock-object/ExtendableClassWithPropertyWithSetHook.php b/tests/_files/mock-object/ExtendableClassWithPropertyWithSetHook.php new file mode 100644 index 00000000000..33332cbf4f9 --- /dev/null +++ b/tests/_files/mock-object/ExtendableClassWithPropertyWithSetHook.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class ExtendableClassWithPropertyWithSetHook +{ + public string $property { + set(string $value) { + $this->property = $value; + } + } +} diff --git a/tests/_files/mock-object/ExtendableReadonlyClass.php b/tests/_files/mock-object/ExtendableReadonlyClass.php new file mode 100644 index 00000000000..1a1673ba3ee --- /dev/null +++ b/tests/_files/mock-object/ExtendableReadonlyClass.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +readonly class ExtendableReadonlyClass +{ + public function __construct(private mixed $value) + { + } + + public function value(): mixed + { + return $this->value; + } +} diff --git a/tests/_files/mock-object/ExtendableReadonlyClassWithCloneMethod.php b/tests/_files/mock-object/ExtendableReadonlyClassWithCloneMethod.php new file mode 100644 index 00000000000..5f8d9701c03 --- /dev/null +++ b/tests/_files/mock-object/ExtendableReadonlyClassWithCloneMethod.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +use Exception; + +readonly class ExtendableReadonlyClassWithCloneMethod +{ + /** + * @throws Exception + */ + public function __clone(): void + { + throw new Exception(__METHOD__); + } + + public function doSomething(): bool + { + return true; + } +} diff --git a/tests/_files/mock-object/FinalClass.php b/tests/_files/mock-object/FinalClass.php new file mode 100644 index 00000000000..c08f5fbdcea --- /dev/null +++ b/tests/_files/mock-object/FinalClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +final class FinalClass +{ + private $value; + + public function __construct($value) + { + $this->value = $value; + } + + public function value() + { + return $this->value; + } +} diff --git a/tests/_files/mock-object/InterfaceWithImplicitProtocol.php b/tests/_files/mock-object/InterfaceWithImplicitProtocol.php new file mode 100644 index 00000000000..6deb63e19b3 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithImplicitProtocol.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithImplicitProtocol +{ + public function one(): void; + + public function two(): void; +} diff --git a/tests/_files/mock-object/InterfaceWithMethodThatHasDefaultParameterValues.php b/tests/_files/mock-object/InterfaceWithMethodThatHasDefaultParameterValues.php new file mode 100644 index 00000000000..7b10933e685 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithMethodThatHasDefaultParameterValues.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithMethodThatHasDefaultParameterValues +{ + public function doSomething(int $a, int $b = 1): int; +} diff --git a/tests/_files/mock-object/InterfaceWithMethodThatReturnsSelf.php b/tests/_files/mock-object/InterfaceWithMethodThatReturnsSelf.php new file mode 100644 index 00000000000..794feed342c --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithMethodThatReturnsSelf.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithMethodThatReturnsSelf +{ + public function doSomething(): self; +} diff --git a/tests/_files/mock-object/InterfaceWithMethodThatReturnsStatic.php b/tests/_files/mock-object/InterfaceWithMethodThatReturnsStatic.php new file mode 100644 index 00000000000..fd806494803 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithMethodThatReturnsStatic.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithMethodThatReturnsStatic +{ + public function doSomething(): static; +} diff --git a/tests/_files/mock-object/InterfaceWithNeverReturningMethod.php b/tests/_files/mock-object/InterfaceWithNeverReturningMethod.php new file mode 100644 index 00000000000..7d151a486d7 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithNeverReturningMethod.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithNeverReturningMethod +{ + public function m(): never; +} diff --git a/tests/_files/mock-object/InterfaceWithPropertyWithGetHook.php b/tests/_files/mock-object/InterfaceWithPropertyWithGetHook.php new file mode 100644 index 00000000000..33578e78da7 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithPropertyWithGetHook.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithPropertyWithGetHook +{ + public string $property { get; } +} diff --git a/tests/_files/mock-object/InterfaceWithPropertyWithSetHook.php b/tests/_files/mock-object/InterfaceWithPropertyWithSetHook.php new file mode 100644 index 00000000000..c455fea1fbe --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithPropertyWithSetHook.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithPropertyWithSetHook +{ + public string $property { set; } +} diff --git a/tests/_files/mock-object/InterfaceWithReturnTypeDeclaration.php b/tests/_files/mock-object/InterfaceWithReturnTypeDeclaration.php new file mode 100644 index 00000000000..b4f474cc3c4 --- /dev/null +++ b/tests/_files/mock-object/InterfaceWithReturnTypeDeclaration.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface InterfaceWithReturnTypeDeclaration +{ + public function __toString(): string; + + public function doSomething(): bool; + + public function doSomethingElse(int $x): int; + + public function selfReference(): self; + + public function returnsNullOrString(): ?string; +} diff --git a/tests/_files/mock-object/Issue6174.php b/tests/_files/mock-object/Issue6174.php new file mode 100644 index 00000000000..dd3d9c32484 --- /dev/null +++ b/tests/_files/mock-object/Issue6174.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface Issue6174 +{ + public function methodNullDefault(?string $param, ?string $nullDefault = null): string; + + public function methodStringDefault(?string $param, ?string $stringDefault = 'something'): string; +} diff --git a/tests/_files/mock-object/MethodWIthVariadicVariables.php b/tests/_files/mock-object/MethodWIthVariadicVariables.php new file mode 100644 index 00000000000..759a08ca766 --- /dev/null +++ b/tests/_files/mock-object/MethodWIthVariadicVariables.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class MethodWIthVariadicVariables +{ + public function testVariadic(string $foo, mixed ...$arguments): array + { + return [$foo, ...$arguments]; + } +} diff --git a/tests/_files/mock-object/TestProxyFixture.php b/tests/_files/mock-object/TestProxyFixture.php new file mode 100644 index 00000000000..d41f16dcece --- /dev/null +++ b/tests/_files/mock-object/TestProxyFixture.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class TestProxyFixture +{ + public function returnString(): string + { + return 'result'; + } +} diff --git a/tests/_files/mock-object/TraitWithConcreteAndAbstractMethod.php b/tests/_files/mock-object/TraitWithConcreteAndAbstractMethod.php new file mode 100644 index 00000000000..3ae3da5f0c1 --- /dev/null +++ b/tests/_files/mock-object/TraitWithConcreteAndAbstractMethod.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +trait TraitWithConcreteAndAbstractMethod +{ + public function concreteMethod(): bool + { + return $this->abstractMethod(); + } + + abstract public function abstractMethod(): bool; +} diff --git a/tests/_files/mock-object/YetAnotherInterface.php b/tests/_files/mock-object/YetAnotherInterface.php new file mode 100644 index 00000000000..1c6cf009f6c --- /dev/null +++ b/tests/_files/mock-object/YetAnotherInterface.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +interface YetAnotherInterface +{ + public function doSomethingElseEntirely(); +} diff --git a/tests/_files/namespace/someNamespaceA/NamespacedClass.php b/tests/_files/namespace/someNamespaceA/NamespacedClass.php new file mode 100644 index 00000000000..6beac955481 --- /dev/null +++ b/tests/_files/namespace/someNamespaceA/NamespacedClass.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\someNamespaceA; + +class NamespacedClass +{ +} diff --git a/tests/_files/namespace/someNamespaceB/NamespacedClass.php b/tests/_files/namespace/someNamespaceB/NamespacedClass.php new file mode 100644 index 00000000000..420b371510b --- /dev/null +++ b/tests/_files/namespace/someNamespaceB/NamespacedClass.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\someNamespaceB; + +class NamespacedClass +{ +} diff --git a/tests/_files/phpt-for-coverage.phpt b/tests/_files/phpt-for-coverage.phpt new file mode 100644 index 00000000000..2fb623afa49 --- /dev/null +++ b/tests/_files/phpt-for-coverage.phpt @@ -0,0 +1,8 @@ +--TEST-- +PHPT for testing coverage +--FILE-- +publicMethod(); +--EXPECT-- diff --git a/tests/_files/phpt-for-multiwhitelist-coverage.phpt b/tests/_files/phpt-for-multiwhitelist-coverage.phpt new file mode 100644 index 00000000000..9ac0763dc6b --- /dev/null +++ b/tests/_files/phpt-for-multiwhitelist-coverage.phpt @@ -0,0 +1,10 @@ +--TEST-- +PHPT for testing coverage using multiple whitespace arguments +--FILE-- +publicMethod(); +$anotherCoveredClass = new SampleClass(1, 2, 'a'); +$testing = $anotherCoveredClass->a; +--EXPECT-- diff --git a/tests/_files/phpt-unsupported-section.phpt b/tests/_files/phpt-unsupported-section.phpt new file mode 100644 index 00000000000..9bcf515a501 --- /dev/null +++ b/tests/_files/phpt-unsupported-section.phpt @@ -0,0 +1,9 @@ +--TEST-- +PHPT runner handles unsupported --SECTION-- gracefully +--FILE-- + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function explode; +use function extension_loaded; +use function getenv; +use function in_array; +use function ini_get; +use function phpversion; +use function version_compare; +use function xdebug_info; + +if (extension_loaded('pcov')) { + return; +} + +if (!extension_loaded('xdebug')) { + print 'skip: This test requires a code coverage driver'; + + return; +} + +if (version_compare(phpversion('xdebug'), '3.1', '>=') && in_array('coverage', xdebug_info('mode'), true)) { + return; +} + +$mode = getenv('XDEBUG_MODE'); + +if ($mode === false || $mode === '') { + $mode = ini_get('xdebug.mode'); +} + +if ($mode === false || + !in_array('coverage', explode(',', $mode), true)) { + print 'skip: XDEBUG_MODE=coverage or xdebug.mode=coverage has to be set'; +} diff --git a/tests/_files/source-filter/a/PrefixSuffix.php b/tests/_files/source-filter/a/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/.hidden/PrefixSuffix.php b/tests/_files/source-filter/a/c/.hidden/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/Prefix.php b/tests/_files/source-filter/a/c/Prefix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/PrefixSuffix.php b/tests/_files/source-filter/a/c/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/Suffix.php b/tests/_files/source-filter/a/c/Suffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/d/Prefix.php b/tests/_files/source-filter/a/c/d/Prefix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/d/PrefixSuffix.php b/tests/_files/source-filter/a/c/d/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/a/c/d/Suffix.php b/tests/_files/source-filter/a/c/d/Suffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/PrefixSuffix.php b/tests/_files/source-filter/b/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/e/PrefixExampleSuffix.php b/tests/_files/source-filter/b/e/PrefixExampleSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/e/PrefixSuffix.php b/tests/_files/source-filter/b/e/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/e/g/PrefixSuffix.php b/tests/_files/source-filter/b/e/g/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/f/PrefixSuffix.php b/tests/_files/source-filter/b/f/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/_files/source-filter/b/f/h/PrefixSuffix.php b/tests/_files/source-filter/b/f/h/PrefixSuffix.php new file mode 100644 index 00000000000..e69de29bb2d diff --git a/Tests/_files/structureAttributesAreSameButValuesAreNot.xml b/tests/_files/structureAttributesAreSameButValuesAreNot.xml similarity index 100% rename from Tests/_files/structureAttributesAreSameButValuesAreNot.xml rename to tests/_files/structureAttributesAreSameButValuesAreNot.xml diff --git a/Tests/_files/structureExpected.xml b/tests/_files/structureExpected.xml similarity index 100% rename from Tests/_files/structureExpected.xml rename to tests/_files/structureExpected.xml diff --git a/Tests/_files/structureIgnoreTextNodes.xml b/tests/_files/structureIgnoreTextNodes.xml similarity index 95% rename from Tests/_files/structureIgnoreTextNodes.xml rename to tests/_files/structureIgnoreTextNodes.xml index 177e2bfdcca..0771b60ca37 100644 --- a/Tests/_files/structureIgnoreTextNodes.xml +++ b/tests/_files/structureIgnoreTextNodes.xml @@ -1,13 +1,13 @@ - textnode + textnode textnode - textnode + textnode Image 1: Dette er en test caption - textnode + textnode diff --git a/Tests/_files/structureIsSameButDataIsNot.xml b/tests/_files/structureIsSameButDataIsNot.xml similarity index 100% rename from Tests/_files/structureIsSameButDataIsNot.xml rename to tests/_files/structureIsSameButDataIsNot.xml diff --git a/Tests/_files/structureWrongNumberOfAttributes.xml b/tests/_files/structureWrongNumberOfAttributes.xml similarity index 100% rename from Tests/_files/structureWrongNumberOfAttributes.xml rename to tests/_files/structureWrongNumberOfAttributes.xml diff --git a/Tests/_files/structureWrongNumberOfNodes.xml b/tests/_files/structureWrongNumberOfNodes.xml similarity index 100% rename from Tests/_files/structureWrongNumberOfNodes.xml rename to tests/_files/structureWrongNumberOfNodes.xml diff --git a/tests/_files/success.phpt b/tests/_files/success.phpt new file mode 100644 index 00000000000..d47ea41521b --- /dev/null +++ b/tests/_files/success.phpt @@ -0,0 +1,7 @@ +--TEST-- +success +--FILE-- + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +if (!defined('TEST_FILES_PATH')) { + define('TEST_FILES_PATH', __DIR__ . DIRECTORY_SEPARATOR . '_files' . DIRECTORY_SEPARATOR); +} + +$composer = file_exists(__DIR__ . '/../vendor/autoload.php'); +$phar = file_exists(__DIR__ . '/autoload.php'); + +if ($composer && $phar) { + print 'More than one test fixture autoloader is available, exiting.' . PHP_EOL; + + exit(1); +} + +if (!$composer && !$phar) { + print 'No test fixture autoloader was registered, exiting.' . PHP_EOL; + + exit(1); +} + +if ($composer) { + if (!defined('PHPUNIT_COMPOSER_INSTALL')) { + define('PHPUNIT_COMPOSER_INSTALL', dirname(__DIR__) . '/vendor/autoload.php'); + } + + require_once __DIR__ . '/../vendor/autoload.php'; +} + +if ($phar) { + if (!defined('__PHPUNIT_PHAR__')) { + require_once __DIR__ . '/../build/artifacts/phpunit-snapshot.phar'; + } + + require_once __DIR__ . '/autoload.php'; + + $jsonFile = dirname(__DIR__) . '/composer.json'; + $base = dirname($jsonFile); + + foreach (json_decode(file_get_contents($jsonFile), true)['autoload-dev']['files'] as $file) { + require_once $base . DIRECTORY_SEPARATOR . $file; + } +} + +unset($composer, $phar, $jsonFile, $base, $file); diff --git a/tests/end-to-end/_files/BeforeTestMethodWithAttributeTest.php b/tests/end-to-end/_files/BeforeTestMethodWithAttributeTest.php new file mode 100644 index 00000000000..c975d68a36b --- /dev/null +++ b/tests/end-to-end/_files/BeforeTestMethodWithAttributeTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\TestCase; + +final class BeforeTestMethodWithAttributeTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Before] + protected function beforeMethod(): void + { + } +} diff --git a/tests/end-to-end/_files/BeforeTestMethodWithPrioritizedAttributeTest.php b/tests/end-to-end/_files/BeforeTestMethodWithPrioritizedAttributeTest.php new file mode 100644 index 00000000000..053ee663bcf --- /dev/null +++ b/tests/end-to-end/_files/BeforeTestMethodWithPrioritizedAttributeTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\TestCase; + +final class BeforeTestMethodWithPrioritizedAttributeTest extends TestCase +{ + protected function setUp(): void + { + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Before(priority: 1)] + protected function beforeMethodWithHighPriority(): void + { + } + + #[Before(priority: -1)] + protected function beforeMethodWithLowPriority(): void + { + } +} diff --git a/tests/end-to-end/_files/ChildProcessTest.php b/tests/end-to-end/_files/ChildProcessTest.php new file mode 100644 index 00000000000..bf8270c819d --- /dev/null +++ b/tests/end-to-end/_files/ChildProcessTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function pcntl_fork; +use function pcntl_wait; +use PHPUnit\Framework\TestCase; + +final class ChildProcessTest extends TestCase +{ + public function testChildProcessOutput(): void + { + $child = pcntl_fork(); + $this->assertGreaterThan(-1, $child); + + if ($child) { + pcntl_wait($child); + $this->assertTrue(true); + } else { + exit(0); + } + } +} diff --git a/tests/end-to-end/_files/ExpectingExceptionsTest.php b/tests/end-to-end/_files/ExpectingExceptionsTest.php new file mode 100644 index 00000000000..b49de10f512 --- /dev/null +++ b/tests/end-to-end/_files/ExpectingExceptionsTest.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ExpectingExceptionsTest extends TestCase +{ + public function test_expectException_and_expected_exception_is_thrown(): void + { + $this->expectException(Exception::class); + + throw new Exception; + } + + public function test_expectException_and_expected_exception_is_not_thrown(): void + { + $this->expectException(Exception::class); + } + + public function test_expectException_and_expectExceptionMessage_and_expected_exception_is_thrown_and_has_expected_message(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('message'); + + throw new Exception('message'); + } + + public function test_expectExceptionMessage_and_exception_is_thrown_and_has_expected_message(): void + { + $this->expectExceptionMessage('message'); + + throw new Exception('message'); + } + + public function test_expectException_and_expectExceptionMessage_and_expected_exception_is_thrown_but_does_not_have_expected_message(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('message'); + + throw new Exception; + } + + public function test_expectExceptionMessage_and_exception_is_thrown_but_does_not_have_expected_message(): void + { + $this->expectExceptionMessage('message'); + + throw new Exception; + } + + public function test_expectExceptionMessage_and_no_exception_is_thrown(): void + { + $this->expectExceptionMessage('message'); + } + + public function test_expectException_and_expectExceptionMessageMatches_and_expected_exception_is_thrown_and_has_expected_message(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/message/'); + + throw new Exception('message'); + } + + public function test_expectExceptionMessageMatches_and_exception_is_thrown_and_has_expected_message(): void + { + $this->expectExceptionMessageMatches('/message/'); + + throw new Exception('message'); + } + + public function test_expectException_and_expectExceptionMessageMatches_and_expected_exception_is_thrown_but_does_not_have_expected_message(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessageMatches('/message/'); + + throw new Exception; + } + + public function test_expectExceptionMessageMatches_and_exception_is_thrown_but_does_not_have_expected_message(): void + { + $this->expectExceptionMessageMatches('/message/'); + + throw new Exception; + } + + public function test_expectExceptionMessageMatches_and_no_exception_is_thrown(): void + { + $this->expectExceptionMessageMatches('/message/'); + } + + public function test_expectException_and_expectExceptionCode_and_expected_exception_is_thrown_and_has_expected_code(): void + { + $this->expectException(Exception::class); + $this->expectExceptionCode(1234); + + throw new Exception(code: 1234); + } + + public function test_expectExceptionCode_and_exception_is_thrown_and_has_expected_code(): void + { + $this->expectExceptionCode(1234); + + throw new Exception(code: 1234); + } + + public function test_expectException_and_expectExceptionCode_and_expected_exception_is_thrown_but_does_not_have_expected_code(): void + { + $this->expectException(Exception::class); + $this->expectExceptionCode(1234); + + throw new Exception; + } + + public function test_expectExceptionCode_and_exception_is_thrown_but_does_not_have_expected_code(): void + { + $this->expectExceptionCode(1234); + + throw new Exception; + } + + public function test_expectExceptionCode_and_no_exception_is_thrown(): void + { + $this->expectExceptionCode(1234); + } + + public function test_expectExceptionObject_and_expected_exception_is_thrown(): void + { + $this->expectExceptionObject(new Exception('message', 1234)); + + throw new Exception('message', 1234); + } + + public function test_expectExceptionObject_and_expected_exception_is_not_thrown(): void + { + $this->expectExceptionObject(new Exception('message', 1234)); + + throw new Exception('not-the-message', 5678); + } + + public function test_expectExceptionObject_and_no_exception_is_thrown(): void + { + $this->expectExceptionObject(new Exception('message', 1234)); + } +} diff --git a/tests/end-to-end/_files/HookMethodsOrderTest.php b/tests/end-to-end/_files/HookMethodsOrderTest.php new file mode 100644 index 00000000000..882556c0d6c --- /dev/null +++ b/tests/end-to-end/_files/HookMethodsOrderTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; + +final class HookMethodsOrderTest extends HookMethodsOrderTestCase +{ + protected function setUp(): void + { + } + + protected function tearDown(): void + { + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Before] + protected function beforeSecond(): void + { + } + + #[Before] + protected function beforeFirst(): void + { + } + + #[Before(priority: 1)] + protected function beforeWithPriority(): void + { + } + + #[After] + protected function afterFirst(): void + { + } + + #[After] + protected function afterSecond(): void + { + } + + #[After(priority: 1)] + protected function afterWithPriority(): void + { + } +} diff --git a/tests/end-to-end/_files/HookMethodsOrderTestCase.php b/tests/end-to-end/_files/HookMethodsOrderTestCase.php new file mode 100644 index 00000000000..39f7554c8bd --- /dev/null +++ b/tests/end-to-end/_files/HookMethodsOrderTestCase.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\TestCase; + +abstract class HookMethodsOrderTestCase extends TestCase +{ + #[Before] + protected function beforeInParent(): void + { + } + + #[Before(priority: 1)] + protected function beforeWithPriorityInParent(): void + { + } + + #[After] + protected function afterInParent(): void + { + } + + #[After(priority: 1)] + protected function afterWithPriorityInParent(): void + { + } +} diff --git a/tests/end-to-end/_files/OutcomesAndIssuesTest.php b/tests/end-to-end/_files/OutcomesAndIssuesTest.php new file mode 100644 index 00000000000..3def81c2f85 --- /dev/null +++ b/tests/end-to-end/_files/OutcomesAndIssuesTest.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Exception; +use PHPUnit\Framework\TestCase; + +final class OutcomesAndIssuesTest extends TestCase +{ + public function testSuccessWithoutIssues(): void + { + $this->assertTrue(true); + } + + public function testSuccessWithRisky(): void + { + } + + public function testSuccessWithDeprecation(): void + { + trigger_error('deprecation message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testSuccessWithNotice(): void + { + trigger_error('notice message', E_USER_NOTICE); + + $this->assertTrue(true); + } + + public function testSuccessWithWarning(): void + { + trigger_error('warning message', E_USER_WARNING); + + $this->assertTrue(true); + } + + public function testFailWithDeprecation(): void + { + trigger_error('deprecation message', E_USER_DEPRECATED); + + $this->assertTrue(false); + } + + public function testFailWithNotice(): void + { + trigger_error('notice message', E_USER_NOTICE); + + $this->assertTrue(false); + } + + public function testFailWithWarning(): void + { + trigger_error('warning message', E_USER_WARNING); + + $this->assertTrue(false); + } + + public function testErrorWithDeprecation(): void + { + trigger_error('deprecation message', E_USER_DEPRECATED); + + throw new Exception('exception message'); + } + + public function testErrorWithNotice(): void + { + trigger_error('notice message', E_USER_NOTICE); + + throw new Exception('exception message'); + } + + public function testErrorWithWarning(): void + { + trigger_error('warning message', E_USER_WARNING); + + throw new Exception('exception message'); + } + + public function testIncompleteWithDeprecation(): void + { + trigger_error('deprecation message', E_USER_DEPRECATED); + + $this->markTestIncomplete('incomplete message'); + } + + public function testIncompleteWithNotice(): void + { + trigger_error('notice message', E_USER_NOTICE); + + $this->markTestIncomplete('incomplete message'); + } + + public function testIncompleteWithWarning(): void + { + trigger_error('warning message', E_USER_WARNING); + + $this->markTestIncomplete('incomplete message'); + } + + public function testSkippedWithDeprecation(): void + { + trigger_error('deprecation message', E_USER_DEPRECATED); + + $this->markTestSkipped('skipped message'); + } + + public function testSkippedWithNotice(): void + { + trigger_error('notice message', E_USER_NOTICE); + + $this->markTestSkipped('skipped message'); + } + + public function testSkippedWithWarning(): void + { + trigger_error('warning message', E_USER_WARNING); + + $this->markTestSkipped('skipped message'); + } +} diff --git a/tests/end-to-end/_files/TestDataProviderExternalAndDataProviderTest.php b/tests/end-to-end/_files/TestDataProviderExternalAndDataProviderTest.php new file mode 100644 index 00000000000..74f151f4ec5 --- /dev/null +++ b/tests/end-to-end/_files/TestDataProviderExternalAndDataProviderTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\TestCase; + +final class TestDataProviderExternalAndDataProviderTest extends TestCase +{ + public static function externalProvider(): iterable + { + yield 'foo' => ['bar', 'baz']; + } + + public static function provider(): iterable + { + yield 'foo2' => ['bar', 'baz']; + } + + #[DataProvider('provider')] + #[DataProviderExternal(self::class, 'externalProvider')] + public function testWithDifferentProviderTypes($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TestProcessIsolationWithDataProvider.php b/tests/end-to-end/_files/TestProcessIsolationWithDataProvider.php new file mode 100644 index 00000000000..9369eb9010e --- /dev/null +++ b/tests/end-to-end/_files/TestProcessIsolationWithDataProvider.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class TestProcessIsolationWithDataProvider extends TestCase +{ + public static function greetDataProvider(): iterable + { + yield ['Hello world!']; + } + + #[RunInSeparateProcess] + #[DataProvider('greetDataProvider')] + public function testInIsolationWithProvider(string $expected): void + { + $this->assertSame($expected, 'Hello world!'); + } +} diff --git a/tests/end-to-end/_files/TestWithAndTestWithJsonDataProviderTest.php b/tests/end-to-end/_files/TestWithAndTestWithJsonDataProviderTest.php new file mode 100644 index 00000000000..cc86be436c1 --- /dev/null +++ b/tests/end-to-end/_files/TestWithAndTestWithJsonDataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\TestCase; + +final class TestWithAndTestWithJsonDataProviderTest extends TestCase +{ + public static function provider(): iterable + { + yield 'foo' => ['bar', 'baz']; + } + + #[TestWith(['a', 'b'], 'foo')] + #[TestWithJson('[1, 2]')] + public function testWithDifferentProviderTypes($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TestWithAttributeAndDataProviderTest.php b/tests/end-to-end/_files/TestWithAttributeAndDataProviderTest.php new file mode 100644 index 00000000000..3fa138c9516 --- /dev/null +++ b/tests/end-to-end/_files/TestWithAttributeAndDataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\TestCase; + +final class TestWithAttributeAndDataProviderTest extends TestCase +{ + public static function provider(): iterable + { + yield 'foo' => ['bar', 'baz']; + } + + #[TestWith(['a', 'b'], 'foo')] + #[DataProvider('provider')] + public function testWithDifferentProviderTypes($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TestWithAttributeAndExternalDataProviderTest.php b/tests/end-to-end/_files/TestWithAttributeAndExternalDataProviderTest.php new file mode 100644 index 00000000000..e9803287adc --- /dev/null +++ b/tests/end-to-end/_files/TestWithAttributeAndExternalDataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\TestCase; + +final class TestWithAttributeAndExternalDataProviderTest extends TestCase +{ + public static function provider(): iterable + { + yield 'foo' => ['bar', 'baz']; + } + + #[TestWith(['a', 'b'], 'foo')] + #[DataProviderExternal(self::class, 'provider')] + public function testWithDifferentProviderTypes($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TestWithJsonAttributeAndDataProviderTest.php b/tests/end-to-end/_files/TestWithJsonAttributeAndDataProviderTest.php new file mode 100644 index 00000000000..f06754d9bcf --- /dev/null +++ b/tests/end-to-end/_files/TestWithJsonAttributeAndDataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\TestCase; + +final class TestWithJsonAttributeAndDataProviderTest extends TestCase +{ + public static function provider(): iterable + { + yield 'foo' => ['bar', 'baz']; + } + + #[TestWithJson('[1, 2, 3]')] + #[DataProvider('provider')] + public function testWithDifferentProviderTypes($one, $two): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TraitTargetedWithCoversClassTest.php b/tests/end-to-end/_files/TraitTargetedWithCoversClassTest.php new file mode 100644 index 00000000000..ec3f79aeff2 --- /dev/null +++ b/tests/end-to-end/_files/TraitTargetedWithCoversClassTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\CoveredTrait; + +#[CoversClass(CoveredTrait::class)] +final class TraitTargetedWithCoversClassTest extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TraitTargetedWithCoversTraitTest.php b/tests/end-to-end/_files/TraitTargetedWithCoversTraitTest.php new file mode 100644 index 00000000000..7e8159c9725 --- /dev/null +++ b/tests/end-to-end/_files/TraitTargetedWithCoversTraitTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\CoveredTrait; + +#[CoversTrait(CoveredTrait::class)] +final class TraitTargetedWithCoversTraitTest extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TraitTargetedWithUsesClassTest.php b/tests/end-to-end/_files/TraitTargetedWithUsesClassTest.php new file mode 100644 index 00000000000..b06f015557a --- /dev/null +++ b/tests/end-to-end/_files/TraitTargetedWithUsesClassTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\CoveredTrait; + +#[UsesClass(CoveredTrait::class)] +final class TraitTargetedWithUsesClassTest extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/TraitTargetedWithUsesTraitTest.php b/tests/end-to-end/_files/TraitTargetedWithUsesTraitTest.php new file mode 100644 index 00000000000..699ccc46d72 --- /dev/null +++ b/tests/end-to-end/_files/TraitTargetedWithUsesTraitTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\DeprecatedAnnotationsTestFixture; + +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\CoveredTrait; + +#[UsesTrait(CoveredTrait::class)] +final class TraitTargetedWithUsesTraitTest extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/UnexpectedOutputTest.php b/tests/end-to-end/_files/UnexpectedOutputTest.php new file mode 100644 index 00000000000..560992ae269 --- /dev/null +++ b/tests/end-to-end/_files/UnexpectedOutputTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function var_dump; +use PHPUnit\Framework\TestCase; + +final class UnexpectedOutputTest extends TestCase +{ + public function testSomething(): void + { + var_dump(['foo' => 'bar']); + + $this->assertSame('something', 'something'); + } +} diff --git a/tests/end-to-end/_files/WithExitTest.php b/tests/end-to-end/_files/WithExitTest.php new file mode 100644 index 00000000000..c3e6c641c5e --- /dev/null +++ b/tests/end-to-end/_files/WithExitTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class WithExitTest extends TestCase +{ + public function testWithMessage(): void + { + $this->assertTrue(true); + + exit('message'); + } + + public function testWithoutMessage(): void + { + $this->assertTrue(true); + + exit(1); + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/phpunit.xml b/tests/end-to-end/_files/attribute-based-filtering/phpunit.xml new file mode 100644 index 00000000000..0025e227829 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/_files/attribute-based-filtering/src/Foo.php b/tests/end-to-end/_files/attribute-based-filtering/src/Foo.php new file mode 100644 index 00000000000..25481906cf8 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/src/Foo.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +final class Foo +{ + public function bar(): bool + { + return true; + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/src/autoload.php b/tests/end-to-end/_files/attribute-based-filtering/src/autoload.php new file mode 100644 index 00000000000..fcbf8ff4050 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/f.php'; + +require __DIR__ . '/Foo.php'; diff --git a/tests/end-to-end/_files/attribute-based-filtering/src/f.php b/tests/end-to-end/_files/attribute-based-filtering/src/f.php new file mode 100644 index 00000000000..0c98490d30e --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/src/f.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +function f(): bool +{ + return true; +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/tests/CoversClassTest.php b/tests/end-to-end/_files/attribute-based-filtering/tests/CoversClassTest.php new file mode 100644 index 00000000000..6a5ecf417b5 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/tests/CoversClassTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Foo::class)] +final class CoversClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/tests/CoversFunctionTest.php b/tests/end-to-end/_files/attribute-based-filtering/tests/CoversFunctionTest.php new file mode 100644 index 00000000000..db81b6e2853 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/tests/CoversFunctionTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\TestCase; + +#[CoversFunction('PHPUnit\TestFixture\AttributeBasedFiltering\f')] +final class CoversFunctionTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/tests/RequiresPhpExtensionTest.php b/tests/end-to-end/_files/attribute-based-filtering/tests/RequiresPhpExtensionTest.php new file mode 100644 index 00000000000..baec8800d1f --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/tests/RequiresPhpExtensionTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpExtension('standard')] +final class RequiresPhpExtensionTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/tests/UsesFunctionTest.php b/tests/end-to-end/_files/attribute-based-filtering/tests/UsesFunctionTest.php new file mode 100644 index 00000000000..aad32abfea7 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/tests/UsesFunctionTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\TestCase; + +#[UsesFunction('PHPUnit\TestFixture\AttributeBasedFiltering\f')] +final class UsesFunctionTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/attribute-based-filtering/tests/UsesTest.php b/tests/end-to-end/_files/attribute-based-filtering/tests/UsesTest.php new file mode 100644 index 00000000000..cffe7cf28e0 --- /dev/null +++ b/tests/end-to-end/_files/attribute-based-filtering/tests/UsesTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributeBasedFiltering; + +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[UsesClass(Foo::class)] +final class UsesTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/.gitignore b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/.gitignore new file mode 100644 index 00000000000..8d20d1464c8 --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/.gitignore @@ -0,0 +1 @@ +baseline.xml diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/phpunit.xml b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/phpunit.xml new file mode 100644 index 00000000000..303ce33dcfc --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/phpunit.xml @@ -0,0 +1,24 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/src/Source.php b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/src/Source.php new file mode 100644 index 00000000000..edb4cc6d5ca --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/src/Source.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Serializable; + +final class Source +{ + public function triggerDeprecation(): void + { + $this->deprecation(); + } + + public function triggerNotice(): void + { + $this->notice(); + } + + public function triggerWarning(): void + { + $this->warning(); + } + + public function triggerPhpDeprecation(): void + { + $this->phpDeprecation(); + } + + public function triggerPhpNoticeAndWarning(): void + { + $this->phpNoticeAndWarning(); + } + + private function deprecation(): void + { + @trigger_error('deprecation', E_USER_DEPRECATED); + } + + private function notice(): void + { + @trigger_error('notice', E_USER_NOTICE); + } + + private function warning(): void + { + @trigger_error('warning', E_USER_WARNING); + } + + private function phpDeprecation(): void + { + @$o = new class implements Serializable + { + public function serialize(): void + { + } + + public function unserialize(string $data): void + { + } + }; + } + + private function phpNoticeAndWarning(): void + { + $o = new class + { + public static $a = 'b'; + }; + + @$o->a; + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/tests/Test.php b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/tests/Test.php new file mode 100644 index 00000000000..4f578129f7c --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed-with-ignored-suppression/tests/Test.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testDeprecation(): void + { + (new Source)->triggerDeprecation(); + + $this->assertTrue(true); + } + + public function testNotice(): void + { + (new Source)->triggerNotice(); + + $this->assertTrue(true); + } + + public function testWarning(): void + { + (new Source)->triggerWarning(); + + $this->assertTrue(true); + } + + public function testPhpDeprecation(): void + { + (new Source)->triggerPhpDeprecation(); + + $this->assertTrue(true); + } + + public function testPhpNoticeAndWarning(): void + { + (new Source)->triggerPhpNoticeAndWarning(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed/.gitignore b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/.gitignore new file mode 100644 index 00000000000..8d20d1464c8 --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/.gitignore @@ -0,0 +1 @@ +baseline.xml diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed/phpunit.xml b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/phpunit.xml new file mode 100644 index 00000000000..fd8b4b4f0bb --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed/src/Source.php b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/src/Source.php new file mode 100644 index 00000000000..edb4cc6d5ca --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/src/Source.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Serializable; + +final class Source +{ + public function triggerDeprecation(): void + { + $this->deprecation(); + } + + public function triggerNotice(): void + { + $this->notice(); + } + + public function triggerWarning(): void + { + $this->warning(); + } + + public function triggerPhpDeprecation(): void + { + $this->phpDeprecation(); + } + + public function triggerPhpNoticeAndWarning(): void + { + $this->phpNoticeAndWarning(); + } + + private function deprecation(): void + { + @trigger_error('deprecation', E_USER_DEPRECATED); + } + + private function notice(): void + { + @trigger_error('notice', E_USER_NOTICE); + } + + private function warning(): void + { + @trigger_error('warning', E_USER_WARNING); + } + + private function phpDeprecation(): void + { + @$o = new class implements Serializable + { + public function serialize(): void + { + } + + public function unserialize(string $data): void + { + } + }; + } + + private function phpNoticeAndWarning(): void + { + $o = new class + { + public static $a = 'b'; + }; + + @$o->a; + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline-suppressed/tests/Test.php b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/tests/Test.php new file mode 100644 index 00000000000..4f578129f7c --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-suppressed/tests/Test.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testDeprecation(): void + { + (new Source)->triggerDeprecation(); + + $this->assertTrue(true); + } + + public function testNotice(): void + { + (new Source)->triggerNotice(); + + $this->assertTrue(true); + } + + public function testWarning(): void + { + (new Source)->triggerWarning(); + + $this->assertTrue(true); + } + + public function testPhpDeprecation(): void + { + (new Source)->triggerPhpDeprecation(); + + $this->assertTrue(true); + } + + public function testPhpNoticeAndWarning(): void + { + (new Source)->triggerPhpNoticeAndWarning(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/.gitignore b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/.gitignore new file mode 100644 index 00000000000..8d20d1464c8 --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/.gitignore @@ -0,0 +1 @@ +baseline.xml diff --git a/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/phpunit.xml b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/phpunit.xml new file mode 100644 index 00000000000..76f34f1f6be --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/phpunit.xml @@ -0,0 +1,17 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/tests/Test.php b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/tests/Test.php new file mode 100644 index 00000000000..3ebb12cdfa3 --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline-with-relative-directory/tests/Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testDeprecation(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline/.gitignore b/tests/end-to-end/_files/baseline/generate-baseline/.gitignore new file mode 100644 index 00000000000..8d20d1464c8 --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline/.gitignore @@ -0,0 +1 @@ +baseline.xml diff --git a/tests/end-to-end/_files/baseline/generate-baseline/phpunit.xml b/tests/end-to-end/_files/baseline/generate-baseline/phpunit.xml new file mode 100644 index 00000000000..fd8b4b4f0bb --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/generate-baseline/src/Source.php b/tests/end-to-end/_files/baseline/generate-baseline/src/Source.php new file mode 100644 index 00000000000..a4a9779a0dc --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline/src/Source.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Serializable; + +final class Source +{ + public function triggerDeprecation(): void + { + $this->deprecation(); + } + + public function triggerNotice(): void + { + $this->notice(); + } + + public function triggerWarning(): void + { + $this->warning(); + } + + public function triggerPhpDeprecation(): void + { + $this->phpDeprecation(); + } + + public function triggerPhpNoticeAndWarning(): void + { + $this->phpNoticeAndWarning(); + } + + private function deprecation(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + } + + private function notice(): void + { + trigger_error('notice', E_USER_NOTICE); + } + + private function warning(): void + { + trigger_error('warning', E_USER_WARNING); + } + + private function phpDeprecation(): void + { + $o = new class implements Serializable + { + public function serialize(): void + { + } + + public function unserialize(string $data): void + { + } + }; + } + + private function phpNoticeAndWarning(): void + { + $o = new class + { + public static $a = 'b'; + }; + + $o->a; + } +} diff --git a/tests/end-to-end/_files/baseline/generate-baseline/tests/Test.php b/tests/end-to-end/_files/baseline/generate-baseline/tests/Test.php new file mode 100644 index 00000000000..4f578129f7c --- /dev/null +++ b/tests/end-to-end/_files/baseline/generate-baseline/tests/Test.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testDeprecation(): void + { + (new Source)->triggerDeprecation(); + + $this->assertTrue(true); + } + + public function testNotice(): void + { + (new Source)->triggerNotice(); + + $this->assertTrue(true); + } + + public function testWarning(): void + { + (new Source)->triggerWarning(); + + $this->assertTrue(true); + } + + public function testPhpDeprecation(): void + { + (new Source)->triggerPhpDeprecation(); + + $this->assertTrue(true); + } + + public function testPhpNoticeAndWarning(): void + { + (new Source)->triggerPhpNoticeAndWarning(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/invalid-baseline/baseline.xml b/tests/end-to-end/_files/baseline/invalid-baseline/baseline.xml new file mode 100644 index 00000000000..b359f0ed462 --- /dev/null +++ b/tests/end-to-end/_files/baseline/invalid-baseline/baseline.xml @@ -0,0 +1,3 @@ + + + diff --git a/tests/end-to-end/_files/baseline/invalid-baseline/phpunit.xml b/tests/end-to-end/_files/baseline/invalid-baseline/phpunit.xml new file mode 100644 index 00000000000..bf0ee15c129 --- /dev/null +++ b/tests/end-to-end/_files/baseline/invalid-baseline/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + + + + diff --git a/tests/end-to-end/_files/baseline/invalid-baseline/tests/Test.php b/tests/end-to-end/_files/baseline/invalid-baseline/tests/Test.php new file mode 100644 index 00000000000..8104eb56178 --- /dev/null +++ b/tests/end-to-end/_files/baseline/invalid-baseline/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/unsupported-baseline/baseline.xml b/tests/end-to-end/_files/baseline/unsupported-baseline/baseline.xml new file mode 100644 index 00000000000..1745bb2c8db --- /dev/null +++ b/tests/end-to-end/_files/baseline/unsupported-baseline/baseline.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/end-to-end/_files/baseline/unsupported-baseline/phpunit.xml b/tests/end-to-end/_files/baseline/unsupported-baseline/phpunit.xml new file mode 100644 index 00000000000..bf0ee15c129 --- /dev/null +++ b/tests/end-to-end/_files/baseline/unsupported-baseline/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + + + + diff --git a/tests/end-to-end/_files/baseline/unsupported-baseline/tests/Test.php b/tests/end-to-end/_files/baseline/unsupported-baseline/tests/Test.php new file mode 100644 index 00000000000..8104eb56178 --- /dev/null +++ b/tests/end-to-end/_files/baseline/unsupported-baseline/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/phpunit.xml b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/phpunit.xml new file mode 100644 index 00000000000..76f34f1f6be --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/phpunit.xml @@ -0,0 +1,17 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/Test.php b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/Test.php new file mode 100644 index 00000000000..3ebb12cdfa3 --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testDeprecation(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/baseline.xml b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/baseline.xml new file mode 100644 index 00000000000..dd8cbc07e02 --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline-in-another-directory/tests/baseline.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/end-to-end/_files/baseline/use-baseline/baseline.xml b/tests/end-to-end/_files/baseline/use-baseline/baseline.xml new file mode 100644 index 00000000000..47be2a96f2a --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline/baseline.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/_files/baseline/use-baseline/phpunit.xml b/tests/end-to-end/_files/baseline/use-baseline/phpunit.xml new file mode 100644 index 00000000000..fd8b4b4f0bb --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/baseline/use-baseline/src/Source.php b/tests/end-to-end/_files/baseline/use-baseline/src/Source.php new file mode 100644 index 00000000000..a4a9779a0dc --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline/src/Source.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Serializable; + +final class Source +{ + public function triggerDeprecation(): void + { + $this->deprecation(); + } + + public function triggerNotice(): void + { + $this->notice(); + } + + public function triggerWarning(): void + { + $this->warning(); + } + + public function triggerPhpDeprecation(): void + { + $this->phpDeprecation(); + } + + public function triggerPhpNoticeAndWarning(): void + { + $this->phpNoticeAndWarning(); + } + + private function deprecation(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + } + + private function notice(): void + { + trigger_error('notice', E_USER_NOTICE); + } + + private function warning(): void + { + trigger_error('warning', E_USER_WARNING); + } + + private function phpDeprecation(): void + { + $o = new class implements Serializable + { + public function serialize(): void + { + } + + public function unserialize(string $data): void + { + } + }; + } + + private function phpNoticeAndWarning(): void + { + $o = new class + { + public static $a = 'b'; + }; + + $o->a; + } +} diff --git a/tests/end-to-end/_files/baseline/use-baseline/tests/SourceTest.php b/tests/end-to-end/_files/baseline/use-baseline/tests/SourceTest.php new file mode 100644 index 00000000000..fc4126239f9 --- /dev/null +++ b/tests/end-to-end/_files/baseline/use-baseline/tests/SourceTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Baseline; + +use PHPUnit\Framework\TestCase; + +final class SourceTest extends TestCase +{ + public function testDeprecation(): void + { + (new Source)->triggerDeprecation(); + + $this->assertTrue(true); + } + + public function testNotice(): void + { + (new Source)->triggerNotice(); + + $this->assertTrue(true); + } + + public function testWarning(): void + { + (new Source)->triggerWarning(); + + $this->assertTrue(true); + } + + public function testPhpDeprecation(): void + { + (new Source)->triggerPhpDeprecation(); + + $this->assertTrue(true); + } + + public function testPhpNoticeAndWarning(): void + { + (new Source)->triggerPhpNoticeAndWarning(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/basic/SuccessTest.php b/tests/end-to-end/_files/basic/SuccessTest.php new file mode 100644 index 00000000000..5c3cbdd64d9 --- /dev/null +++ b/tests/end-to-end/_files/basic/SuccessTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use PHPUnit\Framework\TestCase; + +final class SuccessTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/basic/configuration.basic.xml b/tests/end-to-end/_files/basic/configuration.basic.xml new file mode 100644 index 00000000000..cd1df56d581 --- /dev/null +++ b/tests/end-to-end/_files/basic/configuration.basic.xml @@ -0,0 +1,15 @@ + + + + + unit + + + + + + + diff --git a/tests/end-to-end/_files/basic/unit/SetUpBeforeClassTest.php b/tests/end-to-end/_files/basic/unit/SetUpBeforeClassTest.php new file mode 100644 index 00000000000..7cd527b419c --- /dev/null +++ b/tests/end-to-end/_files/basic/unit/SetUpBeforeClassTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use Exception; +use PHPUnit\Framework\TestCase; + +/** + * Class SetUpBeforeClassTest. + * + * Behaviour to test: + * - setUpBeforeClass() errors do reach the user + * - setUp() is not run + * - how many times is setUpBeforeClass() called? + * - tests are not executed + * + * @see https://github.com/sebastianbergmann/phpunit/issues/2145 + * @see https://github.com/sebastianbergmann/phpunit/issues/3107 + * @see https://github.com/sebastianbergmann/phpunit/issues/3364 + */ +class SetUpBeforeClassTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + throw new Exception('forcing an Exception in setUpBeforeClass()'); + } + + protected function setUp(): void + { + throw new Exception('setUp() should never have been run'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/basic/unit/SetUpTest.php b/tests/end-to-end/_files/basic/unit/SetUpTest.php new file mode 100644 index 00000000000..6a04b650be3 --- /dev/null +++ b/tests/end-to-end/_files/basic/unit/SetUpTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use PHPUnit\Framework\TestCase; +use RuntimeException; + +/** + * Class SetUpBeforeClassTest. + * + * Behaviour to test: + * - setUp() errors reach the user + * - how many times is setUp() called? + * - tests are not executed + * + * @see https://github.com/sebastianbergmann/phpunit/issues/3107 + * @see https://github.com/sebastianbergmann/phpunit/issues/3364 + */ +class SetUpTest extends TestCase +{ + protected function setUp(): void + { + throw new RuntimeException('throw exception in setUp'); + } + + public function testOneWithSetUpException(): void + { + $this->assertTrue(false); + } + + public function testTwoWithSetUpException(): void + { + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/_files/basic/unit/StatusTest.php b/tests/end-to-end/_files/basic/unit/StatusTest.php new file mode 100644 index 00000000000..ad3f7a85c0e --- /dev/null +++ b/tests/end-to-end/_files/basic/unit/StatusTest.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use RuntimeException; + +#[CoversClass('Foo')] +#[UsesClass('Bar')] +#[TestDox('Test result status with and without message')] +class StatusTest extends TestCase +{ + public function testSuccess(): void + { + $this->createMock(AnInterface::class); + + $this->assertTrue(true); + } + + public function testFailure(): void + { + $this->assertTrue(false); + } + + public function testError(): void + { + throw new RuntimeException; + } + + public function testIncomplete(): void + { + $this->markTestIncomplete(); + } + + public function testSkipped(): void + { + $this->markTestSkipped(); + } + + public function testRisky(): void + { + } + + public function testSuccessWithMessage(): void + { + $this->assertTrue(true, 'success with custom message'); + } + + public function testFailureWithMessage(): void + { + $this->assertTrue(false, 'failure with custom message'); + } + + public function testErrorWithMessage(): void + { + throw new RuntimeException('error with custom message'); + } + + public function testIncompleteWithMessage(): void + { + $this->markTestIncomplete('incomplete with custom message'); + } + + #[RequiresPhp('> 9000')] + public function testSkippedByMetadata(): void + { + } + + public function testSkippedWithMessage(): void + { + $this->markTestSkipped('skipped with custom message'); + } + + public function testRiskyWithMessage(): void + { + // Custom messages not implemented for risky status + } +} diff --git a/tests/end-to-end/_files/basic/unit/TearDownAfterClassTest.php b/tests/end-to-end/_files/basic/unit/TearDownAfterClassTest.php new file mode 100644 index 00000000000..87e93d24323 --- /dev/null +++ b/tests/end-to-end/_files/basic/unit/TearDownAfterClassTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use Exception; +use PHPUnit\Framework\TestCase; + +/** + * Class TearDownAfterClassTest. + * + * Behaviour to test: + * - tearDownAfterClass() errors do reach the user + * - tests are executed + * - tearDownAfterClass() should be called and reported once + */ +class TearDownAfterClassTest extends TestCase +{ + public static function tearDownAfterClass(): void + { + throw new Exception('forcing an Exception in tearDownAfterClass()'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/phpunit.xml b/tests/end-to-end/_files/bootstrap-for-test-suite/phpunit.xml new file mode 100644 index 00000000000..1efce2727d0 --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/phpunit.xml @@ -0,0 +1,15 @@ + + + + + tests/one + + + + tests/two + + + diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap.php b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap.php new file mode 100644 index 00000000000..4fce8b0581d --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap.php @@ -0,0 +1,9 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_one.php b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_one.php new file mode 100644 index 00000000000..9a161288b3e --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_one.php @@ -0,0 +1,10 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +$GLOBALS['one'] = true; diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_two.php b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_two.php new file mode 100644 index 00000000000..79abb8796d5 --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/bootstrap/bootstrap_two.php @@ -0,0 +1,10 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +$GLOBALS['two'] = true; diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/tests/one/OneTest.php b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/one/OneTest.php new file mode 100644 index 00000000000..070ddf23988 --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/one/OneTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\BootstrapForTestSuite; + +use PHPUnit\Framework\TestCase; + +final class OneTest extends TestCase +{ + public function testOne(): void + { + $this->assertArrayHasKey('one', $GLOBALS); + } +} diff --git a/tests/end-to-end/_files/bootstrap-for-test-suite/tests/two/TwoTest.php b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/two/TwoTest.php new file mode 100644 index 00000000000..81ef1931805 --- /dev/null +++ b/tests/end-to-end/_files/bootstrap-for-test-suite/tests/two/TwoTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\BootstrapForTestSuite; + +use PHPUnit\Framework\TestCase; + +final class TwoTest extends TestCase +{ + public function testTwo(): void + { + $this->assertArrayHasKey('two', $GLOBALS); + } +} diff --git a/tests/end-to-end/_files/code-coverage-targeting/phpunit.xml b/tests/end-to-end/_files/code-coverage-targeting/phpunit.xml new file mode 100644 index 00000000000..f2074c54f05 --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/code-coverage-targeting/src/SomeClass.php b/tests/end-to-end/_files/code-coverage-targeting/src/SomeClass.php new file mode 100644 index 00000000000..bf59bfbb4d9 --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/src/SomeClass.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\CodeCoverageTargeting\Warnings; + +final readonly class SomeClass +{ +} diff --git a/tests/end-to-end/_files/code-coverage-targeting/tests/CoversAndUsesTest.php b/tests/end-to-end/_files/code-coverage-targeting/tests/CoversAndUsesTest.php new file mode 100644 index 00000000000..2bc46f84440 --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/tests/CoversAndUsesTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\CodeCoverageTargeting\Warnings; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SomeClass::class)] +#[UsesClass(SomeClass::class)] +final class CoversAndUsesTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/code-coverage-targeting/tests/CoversClassCoversNothingTest.php b/tests/end-to-end/_files/code-coverage-targeting/tests/CoversClassCoversNothingTest.php new file mode 100644 index 00000000000..0acf9eef9c8 --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/tests/CoversClassCoversNothingTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\CodeCoverageTargeting\Warnings; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SomeClass::class)] +#[CoversNothing] +final class CoversClassCoversNothingTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateCoversTest.php b/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateCoversTest.php new file mode 100644 index 00000000000..cc49b5816f4 --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateCoversTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\CodeCoverageTargeting\Warnings; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SomeClass::class)] +#[CoversClass(SomeClass::class)] +final class DuplicateCoversTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateUsesTest.php b/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateUsesTest.php new file mode 100644 index 00000000000..09540c491fc --- /dev/null +++ b/tests/end-to-end/_files/code-coverage-targeting/tests/DuplicateUsesTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\CodeCoverageTargeting\Warnings; + +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[UsesClass(SomeClass::class)] +#[UsesClass(SomeClass::class)] +final class DuplicateUsesTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/phpunit.xml b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/phpunit.xml new file mode 100644 index 00000000000..a0695798658 --- /dev/null +++ b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/phpunit.xml @@ -0,0 +1,15 @@ + + + + + tests/unit + + + + tests/end-to-end + + + diff --git a/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/end-to-end/EndToEndTest.php b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/end-to-end/EndToEndTest.php new file mode 100644 index 00000000000..f1bdf6e001e --- /dev/null +++ b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/end-to-end/EndToEndTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +#[DoesNotPerformAssertions] +final class EndToEndTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/unit/UnitTest.php b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/unit/UnitTest.php new file mode 100644 index 00000000000..78dd454303f --- /dev/null +++ b/tests/end-to-end/_files/configuration-file-based-test-selection/defaultTestSuite/tests/unit/UnitTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +#[DoesNotPerformAssertions] +final class UnitTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/_files/configuration-file-based-test-selection/groups/phpunit.xml b/tests/end-to-end/_files/configuration-file-based-test-selection/groups/phpunit.xml new file mode 100644 index 00000000000..b86338c97a0 --- /dev/null +++ b/tests/end-to-end/_files/configuration-file-based-test-selection/groups/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + one + + + diff --git a/tests/end-to-end/_files/configuration-file-based-test-selection/groups/tests/ExampleTest.php b/tests/end-to-end/_files/configuration-file-based-test-selection/groups/tests/ExampleTest.php new file mode 100644 index 00000000000..3f345dff517 --- /dev/null +++ b/tests/end-to-end/_files/configuration-file-based-test-selection/groups/tests/ExampleTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +#[DoesNotPerformAssertions] +final class ExampleTest extends TestCase +{ + #[Group('one')] + public function testOne(): void + { + } + + #[Group('two')] + public function testTwo(): void + { + } +} diff --git a/tests/end-to-end/_files/controlled-garbage-collection/phpunit.xml b/tests/end-to-end/_files/controlled-garbage-collection/phpunit.xml new file mode 100644 index 00000000000..f9e2acbe85e --- /dev/null +++ b/tests/end-to-end/_files/controlled-garbage-collection/phpunit.xml @@ -0,0 +1,12 @@ + + + + + tests + + + diff --git a/tests/end-to-end/_files/controlled-garbage-collection/tests/GarbageCollectionTest.php b/tests/end-to-end/_files/controlled-garbage-collection/tests/GarbageCollectionTest.php new file mode 100644 index 00000000000..a473314e20e --- /dev/null +++ b/tests/end-to-end/_files/controlled-garbage-collection/tests/GarbageCollectionTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\GarbageCollection; + +use PHPUnit\Framework\TestCase; + +final class GarbageCollectionTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/coverage-annotation-based-filter/src/AnnotationFilter.php b/tests/end-to-end/_files/coverage-annotation-based-filter/src/AnnotationFilter.php new file mode 100644 index 00000000000..2049c128a69 --- /dev/null +++ b/tests/end-to-end/_files/coverage-annotation-based-filter/src/AnnotationFilter.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\MockObject; + +class AClass +{ +} diff --git a/tests/end-to-end/_files/coverage-annotation-based-filter/tests/AnnotationFilterTest.php b/tests/end-to-end/_files/coverage-annotation-based-filter/tests/AnnotationFilterTest.php new file mode 100644 index 00000000000..0acfa0839b3 --- /dev/null +++ b/tests/end-to-end/_files/coverage-annotation-based-filter/tests/AnnotationFilterTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class AlternativeSuffixTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } + + public function testThree(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/coverage/coverage-no-tests-when-missing-coverage-driver.phpt b/tests/end-to-end/_files/coverage/coverage-no-tests-when-missing-coverage-driver.phpt new file mode 100644 index 00000000000..96401ed63f9 --- /dev/null +++ b/tests/end-to-end/_files/coverage/coverage-no-tests-when-missing-coverage-driver.phpt @@ -0,0 +1,28 @@ +--TEST-- +Don't run tests when coverage driver is not loaded +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +There was 1 PHPUnit test runner warning: + +1) No code coverage driver available + +No tests executed! + diff --git a/tests/end-to-end/_files/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt b/tests/end-to-end/_files/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt new file mode 100644 index 00000000000..550b65ab507 --- /dev/null +++ b/tests/end-to-end/_files/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt @@ -0,0 +1,30 @@ +--TEST-- +Don't run tests when wrong xdebug mode is set +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +There was 1 PHPUnit test runner warning: + +1) XDEBUG_MODE=coverage (environment variable) or xdebug.mode=coverage (PHP configuration setting) has to be set + +No tests executed! + diff --git a/tests/end-to-end/_files/do-not-fail-on/phpunit.xml b/tests/end-to-end/_files/do-not-fail-on/phpunit.xml new file mode 100644 index 00000000000..0a055bf0064 --- /dev/null +++ b/tests/end-to-end/_files/do-not-fail-on/phpunit.xml @@ -0,0 +1,12 @@ + + + + + tests + + + diff --git a/tests/end-to-end/_files/do-not-fail-on/tests/IssueTest.php b/tests/end-to-end/_files/do-not-fail-on/tests/IssueTest.php new file mode 100644 index 00000000000..d56ab788ef8 --- /dev/null +++ b/tests/end-to-end/_files/do-not-fail-on/tests/IssueTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DoNotFailOn; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; + +final class IssueTest extends TestCase +{ + public function testThatTriggersPhpunitDeprecation(): void + { + EventFacade::emitter()->testTriggeredPhpunitDeprecation( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } + + public function testThatTriggersPhpunitWarning(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } + + public function testThatTriggersDeprecation(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testThatIsSkipped(): void + { + $this->markTestSkipped('message'); + } + + public function testThatIsIncomplete(): void + { + $this->markTestIncomplete('message'); + } + + public function testThatTriggersNotice(): void + { + trigger_error('message', E_USER_NOTICE); + + $this->assertTrue(true); + } + + public function testThatIsRisky(): void + { + } + + public function testThatTriggersWarning(): void + { + trigger_error('message', E_USER_WARNING); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/expect_external.txt b/tests/end-to-end/_files/expect_external.txt new file mode 100644 index 00000000000..4e8779e82dc --- /dev/null +++ b/tests/end-to-end/_files/expect_external.txt @@ -0,0 +1,3 @@ +Hello World +This is line two +and this is line three diff --git a/tests/end-to-end/_files/filter-error-handler/filter-disabled.xml b/tests/end-to-end/_files/filter-error-handler/filter-disabled.xml new file mode 100644 index 00000000000..b5079e29e68 --- /dev/null +++ b/tests/end-to-end/_files/filter-error-handler/filter-disabled.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/filter-error-handler/filter-enabled.xml b/tests/end-to-end/_files/filter-error-handler/filter-enabled.xml new file mode 100644 index 00000000000..7424e4393fb --- /dev/null +++ b/tests/end-to-end/_files/filter-error-handler/filter-enabled.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/filter-error-handler/src/SourceClass.php b/tests/end-to-end/_files/filter-error-handler/src/SourceClass.php new file mode 100644 index 00000000000..224d67684f6 --- /dev/null +++ b/tests/end-to-end/_files/filter-error-handler/src/SourceClass.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\FilterErrorHandler; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; + +final class SourceClass +{ + public function doSomething(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + trigger_error('notice', E_USER_NOTICE); + trigger_error('warning', E_USER_WARNING); + + (new VendorClass)->doSomething(); + } +} diff --git a/tests/end-to-end/_files/filter-error-handler/tests/SourceClassTest.php b/tests/end-to-end/_files/filter-error-handler/tests/SourceClassTest.php new file mode 100644 index 00000000000..2be91534e71 --- /dev/null +++ b/tests/end-to-end/_files/filter-error-handler/tests/SourceClassTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\FilterErrorHandler; + +use PHPUnit\Framework\TestCase; + +final class SourceClassTest extends TestCase +{ + public function testSomething(): void + { + (new SourceClass)->doSomething(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/filter-error-handler/vendor/VendorClass.php b/tests/end-to-end/_files/filter-error-handler/vendor/VendorClass.php new file mode 100644 index 00000000000..cc8dbd5b338 --- /dev/null +++ b/tests/end-to-end/_files/filter-error-handler/vendor/VendorClass.php @@ -0,0 +1,12 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/force-covers-annotation/tests/Test.php b/tests/end-to-end/_files/force-covers-annotation/tests/Test.php new file mode 100644 index 00000000000..a2aa00e57b6 --- /dev/null +++ b/tests/end-to-end/_files/force-covers-annotation/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/groups/phpunit.xml b/tests/end-to-end/_files/groups/phpunit.xml new file mode 100644 index 00000000000..8b2df97afce --- /dev/null +++ b/tests/end-to-end/_files/groups/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/_files/groups/tests/FooTest.php b/tests/end-to-end/_files/groups/tests/FooTest.php new file mode 100644 index 00000000000..53850b69e97 --- /dev/null +++ b/tests/end-to-end/_files/groups/tests/FooTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Groups; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + #[Group('one')] + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Group('two')] + public function testTwo(): void + { + $this->assertTrue(true); + } + + public function testThree(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/listing-tests-and-groups/ExampleAbstractTestCase.php b/tests/end-to-end/_files/listing-tests-and-groups/ExampleAbstractTestCase.php new file mode 100644 index 00000000000..2b1977896c6 --- /dev/null +++ b/tests/end-to-end/_files/listing-tests-and-groups/ExampleAbstractTestCase.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ListingTestsAndGroups; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +abstract class ExampleAbstractTestCase extends TestCase +{ + #[Group('abstract-one')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/listing-tests-and-groups/ExampleExtendingAbstractTest.php b/tests/end-to-end/_files/listing-tests-and-groups/ExampleExtendingAbstractTest.php new file mode 100644 index 00000000000..01e316b4757 --- /dev/null +++ b/tests/end-to-end/_files/listing-tests-and-groups/ExampleExtendingAbstractTest.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ListingTestsAndGroups; + +final class ExampleExtendingAbstractTest extends ExampleAbstractTestCase +{ +} diff --git a/tests/end-to-end/_files/listing-tests-and-groups/ExampleTest.php b/tests/end-to-end/_files/listing-tests-and-groups/ExampleTest.php new file mode 100644 index 00000000000..d4f783d722f --- /dev/null +++ b/tests/end-to-end/_files/listing-tests-and-groups/ExampleTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ListingTestsAndGroups; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +final class ExampleTest extends TestCase +{ + #[Group('one')] + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Group('two')] + public function testTwo(): void + { + $this->assertTrue(true); + } + + #[Group('3')] + public function testThree(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/listing-tests-and-groups/example.phpt b/tests/end-to-end/_files/listing-tests-and-groups/example.phpt new file mode 100644 index 00000000000..412a451c6b7 --- /dev/null +++ b/tests/end-to-end/_files/listing-tests-and-groups/example.phpt @@ -0,0 +1,4 @@ +--TEST-- +This is an example PHPT test, this file is never executed! +--FILE-- +--EXPECT-- diff --git a/tests/end-to-end/_files/log-events-text/Test.php b/tests/end-to-end/_files/log-events-text/Test.php new file mode 100644 index 00000000000..8c21fd3a13f --- /dev/null +++ b/tests/end-to-end/_files/log-events-text/Test.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\LogEventsText; + +use function fopen; +use PHPUnit\Framework\TestCase; +use stdClass; + +final class Test extends TestCase +{ + public function testExportNull(): void + { + $this->assertNull(null); + } + + public function testExportBool(): void + { + $this->assertTrue(true); + } + + public function testExportInt(): void + { + $this->assertSame(1, 1); + } + + public function testExportStr(): void + { + $this->assertSame('hello, world!', 'hello, world!'); + } + + public function testExportArray(): void + { + $arr = [1, 'foo' => 2]; + $this->assertSame($arr, $arr); + } + + public function testExportObject(): void + { + $this->assertSame(new stdClass, new stdClass); + } + + public function testExportResource(): void + { + $this->assertSame(fopen('php://memory', 'rw+'), fopen('php://memory', 'rw+')); + } +} diff --git a/tests/end-to-end/_files/multiple-testsuites/default-test-suite.xml b/tests/end-to-end/_files/multiple-testsuites/default-test-suite.xml new file mode 100644 index 00000000000..1fdf8a59230 --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/default-test-suite.xml @@ -0,0 +1,14 @@ + + + + + tests/unit + + + + tests/end-to-end + + + diff --git a/tests/end-to-end/_files/multiple-testsuites/exclude-group.xml b/tests/end-to-end/_files/multiple-testsuites/exclude-group.xml new file mode 100644 index 00000000000..ce0872c84e2 --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/exclude-group.xml @@ -0,0 +1,19 @@ + + + + + tests/unit + + + + tests/end-to-end + + + + + + default + + + diff --git a/tests/end-to-end/_files/multiple-testsuites/include-group.xml b/tests/end-to-end/_files/multiple-testsuites/include-group.xml new file mode 100644 index 00000000000..d96391fc5a5 --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/include-group.xml @@ -0,0 +1,19 @@ + + + + + tests/unit + + + + tests/end-to-end + + + + + + default + + + diff --git a/tests/end-to-end/_files/multiple-testsuites/phpunit.xml b/tests/end-to-end/_files/multiple-testsuites/phpunit.xml new file mode 100644 index 00000000000..790b18bdfce --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/phpunit.xml @@ -0,0 +1,13 @@ + + + + + tests/unit + + + + tests/end-to-end + + + diff --git a/tests/end-to-end/_files/multiple-testsuites/tests/end-to-end/BarTest.php b/tests/end-to-end/_files/multiple-testsuites/tests/end-to-end/BarTest.php new file mode 100644 index 00000000000..1b60ecbc17d --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/tests/end-to-end/BarTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class BarTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/multiple-testsuites/tests/unit/FooTest.php b/tests/end-to-end/_files/multiple-testsuites/tests/unit/FooTest.php new file mode 100644 index 00000000000..123c21688f2 --- /dev/null +++ b/tests/end-to-end/_files/multiple-testsuites/tests/unit/FooTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/no-log-cc-override/NoLogNoCc.php b/tests/end-to-end/_files/no-log-cc-override/NoLogNoCc.php new file mode 100644 index 00000000000..092d394fca1 --- /dev/null +++ b/tests/end-to-end/_files/no-log-cc-override/NoLogNoCc.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class NoLogNoCc +{ + public function getTrue(): bool + { + return true; + } +} diff --git a/tests/end-to-end/_files/no-log-cc-override/NoLogNoCcTest.php b/tests/end-to-end/_files/no-log-cc-override/NoLogNoCcTest.php new file mode 100644 index 00000000000..6cb00740fb7 --- /dev/null +++ b/tests/end-to-end/_files/no-log-cc-override/NoLogNoCcTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(NoLogNoCc::class)] +final class NoLogNoCcTest extends TestCase +{ + public function testSuccess(): void + { + $this->assertTrue((new NoLogNoCc)->getTrue()); + } +} diff --git a/tests/end-to-end/_files/no-log-cc-override/phpunit.xml b/tests/end-to-end/_files/no-log-cc-override/phpunit.xml new file mode 100644 index 00000000000..e2920c5bb82 --- /dev/null +++ b/tests/end-to-end/_files/no-log-cc-override/phpunit.xml @@ -0,0 +1,26 @@ + + + + + + + + + + + diff --git a/tests/end-to-end/_files/output-cli-help-color.txt b/tests/end-to-end/_files/output-cli-help-color.txt new file mode 100644 index 00000000000..17eaf24133b --- /dev/null +++ b/tests/end-to-end/_files/output-cli-help-color.txt @@ -0,0 +1,246 @@ +Usage: + phpunit [options] ... + +Configuration: + + --bootstrap   A PHP script that is included before the + tests run + -c|--configuration   Read configuration from XML file + --no-configuration  Ignore default configuration file + (phpunit.xml) + --extension   Register test runner extension with + bootstrap + --no-extensions  Do not register test runner extensions + --include-path   Prepend PHP's include_path with given + path(s) + -d   Sets a php.ini value + --cache-directory   Specify cache directory + --generate-configuration  Generate configuration file with + suggested settings + --migrate-configuration  Migrate configuration file to current + format + --generate-baseline   Generate baseline for issues + --use-baseline   Use baseline to ignore issues + --ignore-baseline  Do not use baseline to ignore issues + +Selection: + + --all  Ignore test selection from XML + configuration file + --list-suites  List available test suites + --testsuite   Only run tests from the specified test + suite(s) + --exclude-testsuite   Exclude tests from the specified test + suite(s) + --list-groups  List available test groups + --group   Only run tests from the specified + group(s) + --exclude-group   Exclude tests from the specified + group(s) + --covers   Only run tests that intend to cover + + --uses   Only run tests that intend to use + --requires-php-extension   Only run tests that require PHP + extension + --list-test-files  List available test files + --list-tests  List available tests + --list-tests-xml   List available tests in XML format + --filter   Filter which tests to run + --exclude-filter   Exclude tests for the specified filter + pattern + --test-suffix   Only search for test in files with + specified suffix(es). Default: + Test.php,.phpt + +Execution: + + --process-isolation  Run each test in a separate PHP process + --globals-backup  Backup and restore $GLOBALS for each + test + --static-backup  Backup and restore static properties for + each test + + --strict-coverage  Be strict about code coverage metadata + --strict-global-state  Be strict about changes to global state + --disallow-test-output  Be strict about output during tests + --enforce-time-limit  Enforce time limit based on test size + --default-time-limit   Timeout in seconds for tests that have + no declared size + --do-not-report-useless-tests  Do not report tests that do not test + anything + + --stop-on-defect  Stop after first error, failure, + warning, or risky test + --stop-on-error  Stop after first error + --stop-on-failure  Stop after first failure + --stop-on-warning  Stop after first warning + --stop-on-risky  Stop after first risky test + --stop-on-deprecation  Stop after first test that triggered a + deprecation + --stop-on-notice  Stop after first test that triggered a + notice + --stop-on-skipped  Stop after first skipped test + --stop-on-incomplete  Stop after first incomplete test + + --fail-on-empty-test-suite  Signal failure using shell exit code + when no tests were run + --fail-on-warning  Signal failure using shell exit code + when a warning was triggered + --fail-on-risky  Signal failure using shell exit code + when a test was considered risky + --fail-on-deprecation  Signal failure using shell exit code + when a deprecation was triggered + --fail-on-phpunit-deprecation  Signal failure using shell exit code + when a PHPUnit deprecation was triggered + --fail-on-phpunit-notice  Signal failure using shell exit code + when a PHPUnit notice was triggered + --fail-on-phpunit-warning  Signal failure using shell exit code + when a PHPUnit warning was triggered + --fail-on-notice  Signal failure using shell exit code + when a notice was triggered + --fail-on-skipped  Signal failure using shell exit code + when a test was skipped + --fail-on-incomplete  Signal failure using shell exit code + when a test was marked incomplete + --fail-on-all-issues  Signal failure using shell exit code + when an issue is triggered + + --do-not-fail-on-empty-test-suite  Do not signal failure using shell exit + code when no tests were run + --do-not-fail-on-warning  Do not signal failure using shell exit + code when a warning was triggered + --do-not-fail-on-risky  Do not signal failure using shell exit + code when a test was considered risky + --do-not-fail-on-deprecation  Do not signal failure using shell exit + code when a deprecation was triggered + --do-not-fail-on-phpunit-deprecation Do not signal failure using shell exit + code when a PHPUnit deprecation was + triggered + --do-not-fail-on-phpunit-notice  Do not signal failure using shell exit + code when a PHPUnit notice was triggered + --do-not-fail-on-phpunit-warning  Do not signal failure using shell exit + code when a PHPUnit warning was + triggered + --do-not-fail-on-notice  Do not signal failure using shell exit + code when a notice was triggered + --do-not-fail-on-skipped  Do not signal failure using shell exit + code when a test was skipped + --do-not-fail-on-incomplete  Do not signal failure using shell exit + code when a test was marked incomplete + + --cache-result  Write test results to cache file + --do-not-cache-result  Do not write test results to cache file + + --order-by   Run tests in order: + default|defects|depends|duration|no-depends|random|reverse|size + --random-order-seed   Use the specified random seed when + running tests in random order + +Reporting: + + --colors   Use colors in output ("never", "auto" or + "always") + --columns   Number of columns to use for progress + output + --columns max  Use maximum number of columns for + progress output + --stderr  Write to STDERR instead of STDOUT + + --no-progress  Disable output of test execution + progress + --no-results  Disable output of test results + --no-output  Disable all output + + --display-incomplete  Display details for incomplete tests + --display-skipped  Display details for skipped tests + --display-deprecations  Display details for deprecations + triggered by tests + --display-phpunit-deprecations  Display details for PHPUnit deprecations + --display-phpunit-notices  Display details for PHPUnit notices + --display-errors  Display details for errors triggered by + tests + --display-notices  Display details for notices triggered by + tests + --display-warnings  Display details for warnings triggered + by tests + --display-all-issues  Display details for all issues that are + triggered + --reverse-list  Print defects in reverse order + + --teamcity  Replace default progress and result + output with TeamCity format + --testdox  Replace default result output with + TestDox format + --testdox-summary  Repeat TestDox output for tests with + errors, failures, or issues + + --debug  Replace default progress and result + output with debugging information + --with-telemetry  Include telemetry information in + debugging information output + +Logging: + + --log-junit   Write test results in JUnit XML format + to file + --log-otr   Write test results in Open Test + Reporting XML format to file + --include-git-information  Include Git information in Open Test + Reporting XML logfile + --log-teamcity   Write test results in TeamCity format to + file + --testdox-html   Write test results in TestDox format + (HTML) to file + --testdox-text   Write test results in TestDox format + (plain text) to file + --log-events-text   Stream events as plain text to file + --log-events-verbose-text   Stream events as plain text with + extended information to file + --no-logging  Ignore logging configured in the XML + configuration file + +Code Coverage: + + --coverage-clover   Write code coverage report in Clover XML + format to file + --coverage-openclover   Write code coverage report in OpenClover + XML format to file + --coverage-cobertura   Write code coverage report in Cobertura + XML format to file + --coverage-crap4j   Write code coverage report in Crap4J XML + format to file + --coverage-html   Write code coverage report in HTML + format to directory + --coverage-php   Write serialized code coverage data to + file + --coverage-text=  Write code coverage report in text + format to file [default: standard + output] + --only-summary-for-coverage-text  Option for code coverage report in text + format: only show summary + --show-uncovered-for-coverage-text  Option for code coverage report in text + format: show uncovered files + --coverage-xml   Write code coverage report in XML format + to directory + --exclude-source-from-xml-coverage  Exclude element from code + coverage report in XML format + --warm-coverage-cache  Warm static analysis cache + --coverage-filter   Include in code coverage reporting + --path-coverage  Report path coverage in addition to line + coverage + --disable-coverage-ignore  Disable metadata for ignoring code + coverage + --no-coverage  Ignore code coverage reporting + configured in the XML configuration file + +Miscellaneous: + + -h|--help  Prints this usage information + --version  Prints the version and exits + --atleast-version   Checks that version is greater than + and exits + --check-version  Checks whether PHPUnit is the latest + version and exits + --check-php-configuration  Checks whether PHP configuration follows + best practices + diff --git a/tests/end-to-end/_files/output-cli-usage.txt b/tests/end-to-end/_files/output-cli-usage.txt new file mode 100644 index 00000000000..a5f994e53b5 --- /dev/null +++ b/tests/end-to-end/_files/output-cli-usage.txt @@ -0,0 +1,160 @@ +PHPUnit %s by Sebastian Bergmann and contributors. + +Usage: + phpunit [options] ... + +Configuration: + + --bootstrap A PHP script that is included before the tests run + -c|--configuration Read configuration from XML file + --no-configuration Ignore default configuration file (phpunit.xml) + --extension Register test runner extension with bootstrap + --no-extensions Do not register test runner extensions + --include-path Prepend PHP's include_path with given path(s) + -d Sets a php.ini value + --cache-directory Specify cache directory + --generate-configuration Generate configuration file with suggested settings + --migrate-configuration Migrate configuration file to current format + --generate-baseline Generate baseline for issues + --use-baseline Use baseline to ignore issues + --ignore-baseline Do not use baseline to ignore issues + +Selection: + + --all Ignore test selection from XML configuration file + --list-suites List available test suites + --testsuite Only run tests from the specified test suite(s) + --exclude-testsuite Exclude tests from the specified test suite(s) + --list-groups List available test groups + --group Only run tests from the specified group(s) + --exclude-group Exclude tests from the specified group(s) + --covers Only run tests that intend to cover + --uses Only run tests that intend to use + --requires-php-extension Only run tests that require PHP extension + --list-test-files List available test files + --list-tests List available tests + --list-tests-xml List available tests in XML format + --filter Filter which tests to run + --exclude-filter Exclude tests for the specified filter pattern + --test-suffix Only search for test in files with specified suffix(es). Default: Test.php,.phpt + +Execution: + + --process-isolation Run each test in a separate PHP process + --globals-backup Backup and restore $GLOBALS for each test + --static-backup Backup and restore static properties for each test + + --strict-coverage Be strict about code coverage metadata + --strict-global-state Be strict about changes to global state + --disallow-test-output Be strict about output during tests + --enforce-time-limit Enforce time limit based on test size + --default-time-limit Timeout in seconds for tests that have no declared size + --do-not-report-useless-tests Do not report tests that do not test anything + + --stop-on-defect Stop after first error, failure, warning, or risky test + --stop-on-error Stop after first error + --stop-on-failure Stop after first failure + --stop-on-warning Stop after first warning + --stop-on-risky Stop after first risky test + --stop-on-deprecation Stop after first test that triggered a deprecation + --stop-on-notice Stop after first test that triggered a notice + --stop-on-skipped Stop after first skipped test + --stop-on-incomplete Stop after first incomplete test + + --fail-on-empty-test-suite Signal failure using shell exit code when no tests were run + --fail-on-warning Signal failure using shell exit code when a warning was triggered + --fail-on-risky Signal failure using shell exit code when a test was considered risky + --fail-on-deprecation Signal failure using shell exit code when a deprecation was triggered + --fail-on-phpunit-deprecation Signal failure using shell exit code when a PHPUnit deprecation was triggered + --fail-on-phpunit-notice Signal failure using shell exit code when a PHPUnit notice was triggered + --fail-on-phpunit-warning Signal failure using shell exit code when a PHPUnit warning was triggered + --fail-on-notice Signal failure using shell exit code when a notice was triggered + --fail-on-skipped Signal failure using shell exit code when a test was skipped + --fail-on-incomplete Signal failure using shell exit code when a test was marked incomplete + --fail-on-all-issues Signal failure using shell exit code when an issue is triggered + + --do-not-fail-on-empty-test-suite Do not signal failure using shell exit code when no tests were run + --do-not-fail-on-warning Do not signal failure using shell exit code when a warning was triggered + --do-not-fail-on-risky Do not signal failure using shell exit code when a test was considered risky + --do-not-fail-on-deprecation Do not signal failure using shell exit code when a deprecation was triggered + --do-not-fail-on-phpunit-deprecation Do not signal failure using shell exit code when a PHPUnit deprecation was triggered + --do-not-fail-on-phpunit-notice Do not signal failure using shell exit code when a PHPUnit notice was triggered + --do-not-fail-on-phpunit-warning Do not signal failure using shell exit code when a PHPUnit warning was triggered + --do-not-fail-on-notice Do not signal failure using shell exit code when a notice was triggered + --do-not-fail-on-skipped Do not signal failure using shell exit code when a test was skipped + --do-not-fail-on-incomplete Do not signal failure using shell exit code when a test was marked incomplete + + --cache-result Write test results to cache file + --do-not-cache-result Do not write test results to cache file + + --order-by Run tests in order: default|defects|depends|duration|no-depends|random|reverse|size + --random-order-seed Use the specified random seed when running tests in random order + +Reporting: + + --colors Use colors in output ("never", "auto" or "always") + --columns Number of columns to use for progress output + --columns max Use maximum number of columns for progress output + --stderr Write to STDERR instead of STDOUT + + --no-progress Disable output of test execution progress + --no-results Disable output of test results + --no-output Disable all output + + --display-incomplete Display details for incomplete tests + --display-skipped Display details for skipped tests + --display-deprecations Display details for deprecations triggered by tests + --display-phpunit-deprecations Display details for PHPUnit deprecations + --display-phpunit-notices Display details for PHPUnit notices + --display-errors Display details for errors triggered by tests + --display-notices Display details for notices triggered by tests + --display-warnings Display details for warnings triggered by tests + --display-all-issues Display details for all issues that are triggered + --reverse-list Print defects in reverse order + + --teamcity Replace default progress and result output with TeamCity format + --testdox Replace default result output with TestDox format + --testdox-summary Repeat TestDox output for tests with errors, failures, or issues + + --debug Replace default progress and result output with debugging information + --with-telemetry Include telemetry information in debugging information output + +Logging: + + --log-junit Write test results in JUnit XML format to file + --log-otr Write test results in Open Test Reporting XML format to file + --include-git-information Include Git information in Open Test Reporting XML logfile + --log-teamcity Write test results in TeamCity format to file + --testdox-html Write test results in TestDox format (HTML) to file + --testdox-text Write test results in TestDox format (plain text) to file + --log-events-text Stream events as plain text to file + --log-events-verbose-text Stream events as plain text with extended information to file + --no-logging Ignore logging configured in the XML configuration file + +Code Coverage: + + --coverage-clover Write code coverage report in Clover XML format to file + --coverage-openclover Write code coverage report in OpenClover XML format to file + --coverage-cobertura Write code coverage report in Cobertura XML format to file + --coverage-crap4j Write code coverage report in Crap4J XML format to file + --coverage-html Write code coverage report in HTML format to directory + --coverage-php Write serialized code coverage data to file + --coverage-text= Write code coverage report in text format to file [default: standard output] + --only-summary-for-coverage-text Option for code coverage report in text format: only show summary + --show-uncovered-for-coverage-text Option for code coverage report in text format: show uncovered files + --coverage-xml Write code coverage report in XML format to directory + --exclude-source-from-xml-coverage Exclude element from code coverage report in XML format + --warm-coverage-cache Warm static analysis cache + --coverage-filter Include in code coverage reporting + --path-coverage Report path coverage in addition to line coverage + --disable-coverage-ignore Disable metadata for ignoring code coverage + --no-coverage Ignore code coverage reporting configured in the XML configuration file + +Miscellaneous: + + -h|--help Prints this usage information + --version Prints the version and exits + --atleast-version Checks that version is greater than and exits + --check-version Checks whether PHPUnit is the latest version and exits + --check-php-configuration Checks whether PHP configuration follows best practices + diff --git a/tests/end-to-end/_files/overlapping-testsuite-configuration/phpunit.xml b/tests/end-to-end/_files/overlapping-testsuite-configuration/phpunit.xml new file mode 100644 index 00000000000..205407cfc12 --- /dev/null +++ b/tests/end-to-end/_files/overlapping-testsuite-configuration/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + + tests + + + diff --git a/tests/end-to-end/_files/overlapping-testsuite-configuration/tests/ExampleTest.php b/tests/end-to-end/_files/overlapping-testsuite-configuration/tests/ExampleTest.php new file mode 100644 index 00000000000..20f1b56624e --- /dev/null +++ b/tests/end-to-end/_files/overlapping-testsuite-configuration/tests/ExampleTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\OverlappingTestSuiteConfiguration; + +use PHPUnit\Framework\TestCase; + +final class ExampleTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/phar-extension/phpunit.xml b/tests/end-to-end/_files/phar-extension/phpunit.xml new file mode 100644 index 00000000000..6fe1bb5596c --- /dev/null +++ b/tests/end-to-end/_files/phar-extension/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + tests + + + diff --git a/tests/end-to-end/_files/phar-extension/tests/Test.php b/tests/end-to-end/_files/phar-extension/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/_files/phar-extension/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/phar-extension/tools/phpunit.d/phpunit-test-extension-1.0.0.phar b/tests/end-to-end/_files/phar-extension/tools/phpunit.d/phpunit-test-extension-1.0.0.phar new file mode 100644 index 00000000000..cfdc373840a Binary files /dev/null and b/tests/end-to-end/_files/phar-extension/tools/phpunit.d/phpunit-test-extension-1.0.0.phar differ diff --git a/tests/end-to-end/_files/phpt-clean-parse-error.phpt b/tests/end-to-end/_files/phpt-clean-parse-error.phpt new file mode 100644 index 00000000000..d9d370b1735 --- /dev/null +++ b/tests/end-to-end/_files/phpt-clean-parse-error.phpt @@ -0,0 +1,11 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5991 +--CLEAN-- + diff --git a/tests/end-to-end/_files/phpt-ini-subprocess.phpt b/tests/end-to-end/_files/phpt-ini-subprocess.phpt new file mode 100644 index 00000000000..e27d5824544 --- /dev/null +++ b/tests/end-to-end/_files/phpt-ini-subprocess.phpt @@ -0,0 +1,14 @@ +--TEST-- +PHPT uses a subprocess when --INI-- is present, even if --SKIPIF-- has no side-effect +--INI-- +error_reporting=-1 +--SKIPIF-- + +--EXPECT-- diff --git a/tests/end-to-end/_files/phpt-skipif-exit-subprocess.phpt b/tests/end-to-end/_files/phpt-skipif-exit-subprocess.phpt new file mode 100644 index 00000000000..c482f593222 --- /dev/null +++ b/tests/end-to-end/_files/phpt-skipif-exit-subprocess.phpt @@ -0,0 +1,9 @@ +--TEST-- +PHPT skip condition which exits the subprocess (side-effect) +--FILE-- + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PhpTSkipIfRequiredFile; + +class SomeClass +{ +} diff --git a/tests/end-to-end/_files/phpt_external.php b/tests/end-to-end/_files/phpt_external.php new file mode 100644 index 00000000000..febd47471a4 --- /dev/null +++ b/tests/end-to-end/_files/phpt_external.php @@ -0,0 +1,12 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +print 'Hello World' . \PHP_EOL; +print 'This is line two' . \PHP_EOL; +print 'and this is line three' . \PHP_EOL; diff --git a/tests/end-to-end/_files/requires_environment_variable/SomeTest.php b/tests/end-to-end/_files/requires_environment_variable/SomeTest.php new file mode 100644 index 00000000000..a58c7ecd828 --- /dev/null +++ b/tests/end-to-end/_files/requires_environment_variable/SomeTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\requires_environment_variable; + +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class SomeTest extends TestCase +{ + #[RequiresEnvironmentVariable('FOO', 'bar')] + public function testShouldNotRunFOOHasWrongValue(): void + { + $this->fail(); + } + + #[RequiresEnvironmentVariable('BAR')] + public function testShouldNotRunBARIsEmpty(): void + { + $this->fail(); + } + + #[RequiresEnvironmentVariable('BAZ')] + public function testShouldNotRunBAZDoesNotExist(): void + { + $this->fail(); + } + + #[RequiresEnvironmentVariable('FOO')] + public function testOneShouldRun(): void + { + $this->assertTrue(true); + } + + #[RequiresEnvironmentVariable('FOO', '1')] + public function testTwoShouldRun(): void + { + $this->assertTrue(true); + } + + #[RequiresEnvironmentVariable('BAR', '')] + public function testThreeShouldRun(): void + { + $this->assertTrue(true); + } + + #[RunInSeparateProcess] + #[RequiresEnvironmentVariable('FOO', '1')] + public function testMustRunInSeparateProcess(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/requires_environment_variable/phpunit.xml b/tests/end-to-end/_files/requires_environment_variable/phpunit.xml new file mode 100644 index 00000000000..f5b185305f0 --- /dev/null +++ b/tests/end-to-end/_files/requires_environment_variable/phpunit.xml @@ -0,0 +1,16 @@ + + + + + SomeTest.php + + + + + + + + diff --git a/tests/end-to-end/_files/size-combinations/LargeMediumTest.php b/tests/end-to-end/_files/size-combinations/LargeMediumTest.php new file mode 100644 index 00000000000..cc48493aca7 --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/LargeMediumTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; + +#[Large] +#[Medium] +final class LargeMediumTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-combinations/LargeSmallTest.php b/tests/end-to-end/_files/size-combinations/LargeSmallTest.php new file mode 100644 index 00000000000..4d426211134 --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/LargeSmallTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Large] +#[Small] +final class LargeSmallTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-combinations/MediumLargeTest.php b/tests/end-to-end/_files/size-combinations/MediumLargeTest.php new file mode 100644 index 00000000000..539a58af2ab --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/MediumLargeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; + +#[Medium] +#[Large] +final class MediumLargeTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-combinations/MediumSmallTest.php b/tests/end-to-end/_files/size-combinations/MediumSmallTest.php new file mode 100644 index 00000000000..96ee5f2ed24 --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/MediumSmallTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Medium] +#[Small] +final class MediumSmallTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-combinations/SmallLargeTest.php b/tests/end-to-end/_files/size-combinations/SmallLargeTest.php new file mode 100644 index 00000000000..50d32db5ee9 --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/SmallLargeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +#[Large] +final class SmallLargeTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-combinations/SmallMediumTest.php b/tests/end-to-end/_files/size-combinations/SmallMediumTest.php new file mode 100644 index 00000000000..e6ad7dbd263 --- /dev/null +++ b/tests/end-to-end/_files/size-combinations/SmallMediumTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeCombinations; + +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +#[Medium] +final class SmallMediumTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-groups/ClassLevelTest.php b/tests/end-to-end/_files/size-groups/ClassLevelTest.php new file mode 100644 index 00000000000..e5cb7a67183 --- /dev/null +++ b/tests/end-to-end/_files/size-groups/ClassLevelTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeGroups; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +#[Group('small')] +#[Group('medium')] +#[Group('large')] +final class ClassLevelTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/size-groups/MethodLevelTest.php b/tests/end-to-end/_files/size-groups/MethodLevelTest.php new file mode 100644 index 00000000000..582c8c192db --- /dev/null +++ b/tests/end-to-end/_files/size-groups/MethodLevelTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SizeGroups; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\TestCase; + +final class MethodLevelTest extends TestCase +{ + #[Group('small')] + #[Group('medium')] + #[Group('large')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/DeprecationTest.php b/tests/end-to-end/_files/stop-on-fail-on/DeprecationTest.php new file mode 100644 index 00000000000..c43da60dc89 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/DeprecationTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; + +final class DeprecationTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } + + public function testThree(): void + { + $this->assertTrue(true); + + EventFacade::emitter()->testTriggeredPhpunitDeprecation( + $this->valueObjectForEvents(), + 'message', + ); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/ErrorTest.php b/tests/end-to-end/_files/stop-on-fail-on/ErrorTest.php new file mode 100644 index 00000000000..e2beaf53062 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/ErrorTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ErrorTest extends TestCase +{ + public function testOne(): void + { + throw new Exception('message'); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/FailureTest.php b/tests/end-to-end/_files/stop-on-fail-on/FailureTest.php new file mode 100644 index 00000000000..88fa527c835 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/FailureTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Framework\TestCase; + +final class FailureTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(false); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/IncompleteTest.php b/tests/end-to-end/_files/stop-on-fail-on/IncompleteTest.php new file mode 100644 index 00000000000..3968700b242 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/IncompleteTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Framework\TestCase; + +final class IncompleteTest extends TestCase +{ + public function testOne(): void + { + $this->markTestIncomplete('message'); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/NoticeTest.php b/tests/end-to-end/_files/stop-on-fail-on/NoticeTest.php new file mode 100644 index 00000000000..aa86486f51e --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/NoticeTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use const E_USER_NOTICE; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class NoticeTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_NOTICE); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/PhpunitNoticeTest.php b/tests/end-to-end/_files/stop-on-fail-on/PhpunitNoticeTest.php new file mode 100644 index 00000000000..1ae3188b44d --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/PhpunitNoticeTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; + +final class PhpunitNoticeTest extends TestCase +{ + public function testOne(): void + { + EventFacade::emitter()->testTriggeredPhpunitNotice( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/RiskyTest.php b/tests/end-to-end/_files/stop-on-fail-on/RiskyTest.php new file mode 100644 index 00000000000..77c497bae55 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/RiskyTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Framework\TestCase; + +final class RiskyTest extends TestCase +{ + public function testOne(): void + { + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/SkippedBeforeClassTest.php b/tests/end-to-end/_files/stop-on-fail-on/SkippedBeforeClassTest.php new file mode 100644 index 00000000000..d3b0ae50906 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/SkippedBeforeClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Framework\TestCase; + +final class SkippedBeforeClassTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + self::markTestSkipped('message'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/SkippedTest.php b/tests/end-to-end/_files/stop-on-fail-on/SkippedTest.php new file mode 100644 index 00000000000..029e5d3adf2 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/SkippedTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use PHPUnit\Framework\TestCase; + +final class SkippedTest extends TestCase +{ + public function testOne(): void + { + $this->markTestSkipped('message'); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/SpecificDeprecationTest.php b/tests/end-to-end/_files/stop-on-fail-on/SpecificDeprecationTest.php new file mode 100644 index 00000000000..c0190ca4a65 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/SpecificDeprecationTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class SpecificDeprecationTest extends TestCase +{ + public function testOne(): void + { + trigger_error('...foo...', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + trigger_error('...bar...', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testThree(): void + { + trigger_error('...baz...', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/stop-on-fail-on/WarningTest.php b/tests/end-to-end/_files/stop-on-fail-on/WarningTest.php new file mode 100644 index 00000000000..4b77ac2cbe2 --- /dev/null +++ b/tests/end-to-end/_files/stop-on-fail-on/WarningTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestRunnerStopping; + +use const E_USER_WARNING; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class WarningTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_WARNING); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/test-attribute-on-hook-methods/TestAttributeOnHookMethodsTest.php b/tests/end-to-end/_files/test-attribute-on-hook-methods/TestAttributeOnHookMethodsTest.php new file mode 100644 index 00000000000..96a16c9a959 --- /dev/null +++ b/tests/end-to-end/_files/test-attribute-on-hook-methods/TestAttributeOnHookMethodsTest.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\AttributesOnTemplateMethods; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +final class TestAttributeOnHookMethodsTest extends TestCase +{ + #[BeforeClass] + #[Test] + public static function before_class(): void + { + } + + #[AfterClass] + #[Test] + public static function after_class(): void + { + } + + #[Test] + public static function setUpBeforeClass(): void + { + } + + #[Test] + public static function tearDownAfterClass(): void + { + } + + #[Test] + public function setUp(): void + { + } + + #[Test] + public function assertPreConditions(): void + { + } + + #[Test] + public function assertPostConditions(): void + { + } + + #[Test] + public function tearDown(): void + { + } + + #[Before] + #[Test] + public function before_method(): void + { + } + + #[PreCondition] + #[Test] + public function pre_condition(): void + { + } + + #[PostCondition] + #[Test] + public function post_condition(): void + { + } + + #[After] + #[Test] + public function after_method(): void + { + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/_files/test-directory-does-not-exist/phpunit.xml b/tests/end-to-end/_files/test-directory-does-not-exist/phpunit.xml new file mode 100644 index 00000000000..1cb2fee9012 --- /dev/null +++ b/tests/end-to-end/_files/test-directory-does-not-exist/phpunit.xml @@ -0,0 +1,9 @@ + + + + + tests + + + diff --git a/tests/end-to-end/_files/transform-exception-hook-method/phpunit.xml b/tests/end-to-end/_files/transform-exception-hook-method/phpunit.xml new file mode 100644 index 00000000000..8bf3399168e --- /dev/null +++ b/tests/end-to-end/_files/transform-exception-hook-method/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/_files/transform-exception-hook-method/src/OriginalException.php b/tests/end-to-end/_files/transform-exception-hook-method/src/OriginalException.php new file mode 100644 index 00000000000..06675cf9223 --- /dev/null +++ b/tests/end-to-end/_files/transform-exception-hook-method/src/OriginalException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TransformExceptionHookMethod; + +use RuntimeException; + +final class OriginalException extends RuntimeException +{ +} diff --git a/tests/end-to-end/_files/transform-exception-hook-method/src/TransformedException.php b/tests/end-to-end/_files/transform-exception-hook-method/src/TransformedException.php new file mode 100644 index 00000000000..8cafbbadf2c --- /dev/null +++ b/tests/end-to-end/_files/transform-exception-hook-method/src/TransformedException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TransformExceptionHookMethod; + +use RuntimeException; + +final class TransformedException extends RuntimeException +{ +} diff --git a/tests/end-to-end/_files/transform-exception-hook-method/src/autoload.php b/tests/end-to-end/_files/transform-exception-hook-method/src/autoload.php new file mode 100644 index 00000000000..ed1c5d175b4 --- /dev/null +++ b/tests/end-to-end/_files/transform-exception-hook-method/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/OriginalException.php'; + +require __DIR__ . '/TransformedException.php'; diff --git a/tests/end-to-end/_files/transform-exception-hook-method/tests/Test.php b/tests/end-to-end/_files/transform-exception-hook-method/tests/Test.php new file mode 100644 index 00000000000..e5c68f016ce --- /dev/null +++ b/tests/end-to-end/_files/transform-exception-hook-method/tests/Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TransformExceptionHookMethod; + +use PHPUnit\Framework\TestCase; +use Throwable; + +final class Test extends TestCase +{ + public function testOne(): void + { + throw new OriginalException('original message'); + } + + protected function transformException(Throwable $t): Throwable + { + return new TransformedException('transformed message'); + } +} diff --git a/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableHookTest.php b/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableHookTest.php new file mode 100644 index 00000000000..58d09c2e6a5 --- /dev/null +++ b/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableHookTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\requires_environment_variable; + +use function getenv; +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\TestCase; + +#[WithEnvironmentVariable('FOO', 'foo')] +final class WithEnvironmentVariableHookTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + self::assertEnvironmentVariablesHaveDefaultValues(); + } + + public static function tearDownAfterClass(): void + { + self::assertEnvironmentVariablesHaveDefaultValues(); + } + + protected function setUp(): void + { + $this->assertEnvironmentVariablesHaveCustomValues(); + } + + protected function tearDown(): void + { + $this->assertEnvironmentVariablesHaveCustomValues(); + } + + #[WithEnvironmentVariable('BAR', 'bar')] + public function testFOOShouldHaveValueErasedFromMethodAttribute(): void + { + $this->assertEnvironmentVariablesHaveCustomValues(); + } + + private function assertEnvironmentVariablesHaveCustomValues(): void + { + $this->assertSame('foo', $_ENV['FOO']); + $this->assertSame('foo', getenv('FOO')); + + $this->assertSame('bar', $_ENV['BAR']); + $this->assertSame('bar', getenv('BAR')); + } + + private static function assertEnvironmentVariablesHaveDefaultValues(): void + { + self::assertSame('1', $_ENV['FOO']); + self::assertSame('1', getenv('FOO')); + + self::assertSame('2', $_ENV['BAR']); + self::assertSame('2', getenv('BAR')); + } +} diff --git a/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableTest.php b/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableTest.php new file mode 100644 index 00000000000..7938ba64e7e --- /dev/null +++ b/tests/end-to-end/_files/with_environment_variable/WithEnvironmentVariableTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\requires_environment_variable; + +use function getenv; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\TestCase; + +#[WithEnvironmentVariable('FOO', 'foo')] +final class WithEnvironmentVariableTest extends TestCase +{ + public function testFOOShouldHaveValueFromClassAttribute1(): void + { + $this->assertSame('foo', $_ENV['FOO']); + $this->assertSame('foo', getenv('FOO')); + } + + #[WithEnvironmentVariable('FOO', 'bar')] + public function testFOOShouldHaveValueOverriddenFromMethodAttribute(): void + { + $this->assertSame('bar', $_ENV['FOO']); + $this->assertSame('bar', getenv('FOO')); + } + + #[Depends('testFOOShouldHaveValueOverriddenFromMethodAttribute')] + public function testFOOShouldHaveValueFromClassAttribute2(): void + { + $this->testFOOShouldHaveValueFromClassAttribute1(); + } + + #[WithEnvironmentVariable('FOO')] + public function testFOOShouldHaveValueErasedFromMethodAttribute(): void + { + $this->assertFalse(isset($_ENV['FOO'])); + $this->assertFalse(getenv('FOO')); + } + + #[Depends('testFOOShouldHaveValueErasedFromMethodAttribute')] + public function testFOOShouldHaveValueFromClassAttribute3(): void + { + $this->testFOOShouldHaveValueFromClassAttribute1(); + } + + #[WithEnvironmentVariable('BAR', 'bar')] + public function testBARShouldHaveValueFromMethodAttribute(): void + { + $this->assertSame('bar', $_ENV['BAR']); + $this->assertSame('bar', getenv('BAR')); + } + + #[Depends('testBARShouldHaveValueFromMethodAttribute')] + public function testBARShouldHaveBeenRestoredToDefaultValue1(): void + { + $this->assertSame('2', $_ENV['BAR']); + $this->assertSame('2', getenv('BAR')); + } + + #[WithEnvironmentVariable('BAR')] + public function testBARShouldHaveValueErasedFromMethodAttribute(): void + { + $this->assertFalse(isset($_ENV['BAR'])); + $this->assertFalse(getenv('BAR')); + } + + #[Depends('testBARShouldHaveValueErasedFromMethodAttribute')] + public function testBARShouldHaveBeenRestoredToDefaultValue2(): void + { + $this->testBARShouldHaveBeenRestoredToDefaultValue1(); + } + + #[WithEnvironmentVariable('BAZ', 'baz')] + public function testBAZShouldHaveValueFromMethodAttribute(): void + { + $this->assertSame('baz', $_ENV['BAZ']); + $this->assertSame('baz', getenv('BAZ')); + } + + #[Depends('testBAZShouldHaveValueFromMethodAttribute')] + public function testBAZShouldHaveBeenErased(): void + { + $this->assertFalse(isset($_ENV['BAZ'])); + $this->assertFalse(getenv('BAZ')); + } + + #[RunInSeparateProcess] + #[WithEnvironmentVariable('BAR', 'bar')] + public function testRunInSeparateProcess(): void + { + $this->assertSame('foo', $_ENV['FOO']); + $this->assertSame('foo', getenv('FOO')); + + $this->assertSame('bar', $_ENV['BAR']); + $this->assertSame('bar', getenv('BAR')); + } + + #[WithEnvironmentVariable('BAZ', '1')] + #[WithEnvironmentVariable('BAZ', '2')] + #[WithEnvironmentVariable('BAZ', '3')] + public function testMultipleAttributesKeepTheLastValue(): void + { + $this->assertSame('3', $_ENV['BAZ']); + $this->assertSame('3', getenv('BAZ')); + } + + #[WithEnvironmentVariable('BAZ', '1')] + #[RequiresEnvironmentVariable('BAZ', '1')] + public function testUsingAlongWithRequiresEnvironmentVariableAttribute(): void + { + $this->assertSame('1', $_ENV['BAZ']); + $this->assertSame('1', getenv('BAZ')); + } +} diff --git a/tests/end-to-end/_files/with_environment_variable/phpunit.xml b/tests/end-to-end/_files/with_environment_variable/phpunit.xml new file mode 100644 index 00000000000..aeed5d5c254 --- /dev/null +++ b/tests/end-to-end/_files/with_environment_variable/phpunit.xml @@ -0,0 +1,17 @@ + + + + + WithEnvironmentVariableTest.php + WithEnvironmentVariableHookTest.php + + + + + + + + diff --git a/tests/end-to-end/baseline/baseline-does-not-exist.phpt b/tests/end-to-end/baseline/baseline-does-not-exist.phpt new file mode 100644 index 00000000000..433970cc605 --- /dev/null +++ b/tests/end-to-end/baseline/baseline-does-not-exist.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit --configuration ../_files/baseline/unsupported-baseline/phpunit.xml --use-baseline does-not-exist.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot read baseline %sdoes-not-exist.xml, file does not exist + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/baseline/baseline-invalid-xml.phpt b/tests/end-to-end/baseline/baseline-invalid-xml.phpt new file mode 100644 index 00000000000..66ff1b95eb0 --- /dev/null +++ b/tests/end-to-end/baseline/baseline-invalid-xml.phpt @@ -0,0 +1,27 @@ +--TEST-- +phpunit --configuration ../_files/baseline/invalid-baseline/phpunit.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot read baseline %sbaseline.xml: %s + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/baseline/generate-baseline-suppressed-with-ignored-suppression.phpt b/tests/end-to-end/baseline/generate-baseline-suppressed-with-ignored-suppression.phpt new file mode 100644 index 00000000000..3d7d271c60c --- /dev/null +++ b/tests/end-to-end/baseline/generate-baseline-suppressed-with-ignored-suppression.phpt @@ -0,0 +1,56 @@ +--TEST-- +phpunit --configuration ../_files/baseline/generate-baseline-suppressed-with-ignored-suppression/phpunit.xml --generate-baseline +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($baseline); + +@unlink($baseline); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DNWDW 5 / 5 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 5, Assertions: 5, Warnings: 2, Deprecations: 2, Notices: 2. + +Baseline written to %sbaseline.xml. + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/baseline/generate-baseline-suppressed.phpt b/tests/end-to-end/baseline/generate-baseline-suppressed.phpt new file mode 100644 index 00000000000..183581c4266 --- /dev/null +++ b/tests/end-to-end/baseline/generate-baseline-suppressed.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --configuration ../_files/baseline/generate-baseline-suppressed/phpunit.xml --generate-baseline +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($baseline); + +@unlink($baseline); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +OK (5 tests, 5 assertions) + +Baseline written to %sbaseline.xml. + + diff --git a/tests/end-to-end/baseline/generate-baseline-with-relative-directory.phpt b/tests/end-to-end/baseline/generate-baseline-with-relative-directory.phpt new file mode 100644 index 00000000000..ec35876498a --- /dev/null +++ b/tests/end-to-end/baseline/generate-baseline-with-relative-directory.phpt @@ -0,0 +1,43 @@ +--TEST-- +phpunit --configuration ../_files/baseline/generate-baseline-with-relative-directory/phpunit.xml --generate-baseline +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($baseline); + +@unlink($baselineAbsolutePath); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +D 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. + +Baseline written to %sbaseline.xml. + + + + + + + + diff --git a/tests/end-to-end/baseline/generate-baseline.phpt b/tests/end-to-end/baseline/generate-baseline.phpt new file mode 100644 index 00000000000..aa5938ec4dd --- /dev/null +++ b/tests/end-to-end/baseline/generate-baseline.phpt @@ -0,0 +1,56 @@ +--TEST-- +phpunit --configuration ../_files/baseline/generate-baseline/phpunit.xml --generate-baseline +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($baseline); + +@unlink($baseline); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DNWDW 5 / 5 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 5, Assertions: 5, Warnings: 2, Deprecations: 2, Notices: 2. + +Baseline written to %sbaseline.xml. + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/baseline/ignore-baseline-testdox.phpt b/tests/end-to-end/baseline/ignore-baseline-testdox.phpt new file mode 100644 index 00000000000..3b501678ca4 --- /dev/null +++ b/tests/end-to-end/baseline/ignore-baseline-testdox.phpt @@ -0,0 +1,105 @@ +--TEST-- +phpunit --configuration ../_files/baseline/use-baseline/phpunit.xml --ignore-baseline --tes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DNWDW 5 / 5 (100%) + +Time: %s, Memory: %s + +Source (PHPUnit\TestFixture\Baseline\Source) + ⚠ Deprecation + ⚠ Notice + ⚠ Warning + ⚠ Php deprecation + ⚠ Php notice and warning + +1 test triggered 1 PHP warning: + +1) %sSource.php:81 +Undefined property: class@anonymous::$a + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpNoticeAndWarning + %sSourceTest.php:44 + +-- + +1 test triggered 1 warning: + +1) %sSource.php:57 +warning + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testWarning + %sSourceTest.php:30 + +-- + +1 test triggered 1 PHP notice: + +1) %sSource.php:81 +Accessing static property class@anonymous::$a as non static + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpNoticeAndWarning + %sSourceTest.php:44 + +-- + +1 test triggered 1 notice: + +1) %sSource.php:52 +notice + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testNotice + %sSourceTest.php:23 + +-- + +1 test triggered 1 PHP deprecation: + +1) %sSource.php:62 +Serializable@anonymous implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpDeprecation + %sSourceTest.php:37 + +-- + +1 test triggered 1 deprecation: + +1) %sSource.php:47 +deprecation + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testDeprecation + %sSourceTest.php:16 + +OK, but there were issues! +Tests: 5, Assertions: 5, Warnings: 2, Deprecations: 2, Notices: 2. diff --git a/tests/end-to-end/baseline/ignore-baseline.phpt b/tests/end-to-end/baseline/ignore-baseline.phpt new file mode 100644 index 00000000000..d3e665662f0 --- /dev/null +++ b/tests/end-to-end/baseline/ignore-baseline.phpt @@ -0,0 +1,97 @@ +--TEST-- +phpunit --configuration ../_files/baseline/use-baseline/phpunit.xml --ignore-baseline +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DNWDW 5 / 5 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHP warning: + +1) %sSource.php:81 +Undefined property: class@anonymous::$a + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpNoticeAndWarning + %sSourceTest.php:44 + +-- + +1 test triggered 1 warning: + +1) %sSource.php:57 +warning + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testWarning + %sSourceTest.php:30 + +-- + +1 test triggered 1 PHP notice: + +1) %sSource.php:81 +Accessing static property class@anonymous::$a as non static + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpNoticeAndWarning + %sSourceTest.php:44 + +-- + +1 test triggered 1 notice: + +1) %sSource.php:52 +notice + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testNotice + %sSourceTest.php:23 + +-- + +1 test triggered 1 PHP deprecation: + +1) %sSource.php:62 +Serializable@anonymous implements the Serializable interface, which is deprecated. Implement __serialize() and __unserialize() instead (or in addition, if support for old PHP versions is necessary) + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testPhpDeprecation + %sSourceTest.php:37 + +-- + +1 test triggered 1 deprecation: + +1) %sSource.php:47 +deprecation + +Triggered by: + +* PHPUnit\TestFixture\Baseline\SourceTest::testDeprecation + %sSourceTest.php:16 + +OK, but there were issues! +Tests: 5, Assertions: 5, Warnings: 2, Deprecations: 2, Notices: 2. diff --git a/tests/end-to-end/baseline/unsupported-baseline.phpt b/tests/end-to-end/baseline/unsupported-baseline.phpt new file mode 100644 index 00000000000..69f12e686dd --- /dev/null +++ b/tests/end-to-end/baseline/unsupported-baseline.phpt @@ -0,0 +1,27 @@ +--TEST-- +phpunit --configuration ../_files/baseline/unsupported-baseline/phpunit.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot read baseline %sbaseline.xml, version 0 is not supported + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/baseline/use-baseline-in-another-directory.phpt b/tests/end-to-end/baseline/use-baseline-in-another-directory.phpt new file mode 100644 index 00000000000..8b3e57bef0b --- /dev/null +++ b/tests/end-to-end/baseline/use-baseline-in-another-directory.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --configuration ../_files/baseline/use-baseline-in-another-directory/phpunit.xml --generate-baseline +--FILE-- +run($_SERVER['argv']); + +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) + +1 issue was ignored by baseline. diff --git a/tests/end-to-end/baseline/use-baseline-testdox.phpt b/tests/end-to-end/baseline/use-baseline-testdox.phpt new file mode 100644 index 00000000000..3bd0e04d640 --- /dev/null +++ b/tests/end-to-end/baseline/use-baseline-testdox.phpt @@ -0,0 +1,32 @@ +--TEST-- +phpunit --configuration ../_files/baseline/use-baseline/phpunit.xml --testdox +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +Source (PHPUnit\TestFixture\Baseline\Source) + ✔ Deprecation + ✔ Notice + ✔ Warning + ✔ Php deprecation + ✔ Php notice and warning + +OK (5 tests, 5 assertions) + +6 issues were ignored by baseline. diff --git a/tests/end-to-end/baseline/use-baseline.phpt b/tests/end-to-end/baseline/use-baseline.phpt new file mode 100644 index 00000000000..6b2b333ed2f --- /dev/null +++ b/tests/end-to-end/baseline/use-baseline.phpt @@ -0,0 +1,24 @@ +--TEST-- +phpunit --configuration ../_files/baseline/use-baseline/phpunit.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +OK (5 tests, 5 assertions) + +6 issues were ignored by baseline. diff --git a/tests/end-to-end/check-php-configuration/failure-with-xdebug.phpt b/tests/end-to-end/check-php-configuration/failure-with-xdebug.phpt new file mode 100644 index 00000000000..0facd455235 --- /dev/null +++ b/tests/end-to-end/check-php-configuration/failure-with-xdebug.phpt @@ -0,0 +1,35 @@ +--TEST-- +phpunit --check-php-configuration (failure, Xdebug loaded) +--SKIPIF-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development + +display_errors = On ... not ok (0) +display_startup_errors = On ... ok +error_reporting = -1 ... ok +xdebug.show_exception_trace = 0 ... ok +zend.assertions = 1 ... ok +assert.exception = 1 ... ok +memory_limit = -1 ... ok diff --git a/tests/end-to-end/check-php-configuration/failure-without-xdebug.phpt b/tests/end-to-end/check-php-configuration/failure-without-xdebug.phpt new file mode 100644 index 00000000000..6c25d6c145d --- /dev/null +++ b/tests/end-to-end/check-php-configuration/failure-without-xdebug.phpt @@ -0,0 +1,33 @@ +--TEST-- +phpunit --check-php-configuration (failure, Xdebug not loaded) +--SKIPIF-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development + +display_errors = On ... not ok (0) +display_startup_errors = On ... ok +error_reporting = -1 ... ok +zend.assertions = 1 ... ok +assert.exception = 1 ... ok +memory_limit = -1 ... ok diff --git a/tests/end-to-end/check-php-configuration/success-with-xdebug.phpt b/tests/end-to-end/check-php-configuration/success-with-xdebug.phpt new file mode 100644 index 00000000000..ac98e46d246 --- /dev/null +++ b/tests/end-to-end/check-php-configuration/success-with-xdebug.phpt @@ -0,0 +1,35 @@ +--TEST-- +phpunit --check-php-configuration (success, Xdebug loaded) +--SKIPIF-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development + +display_errors = On ... ok +display_startup_errors = On ... ok +error_reporting = -1 ... ok +xdebug.show_exception_trace = 0 ... ok +zend.assertions = 1 ... ok +assert.exception = 1 ... ok +memory_limit = -1 ... ok diff --git a/tests/end-to-end/check-php-configuration/success-without-xdebug.phpt b/tests/end-to-end/check-php-configuration/success-without-xdebug.phpt new file mode 100644 index 00000000000..7e8c16deb8e --- /dev/null +++ b/tests/end-to-end/check-php-configuration/success-without-xdebug.phpt @@ -0,0 +1,33 @@ +--TEST-- +phpunit --check-php-configuration (success, Xdebug not loaded) +--SKIPIF-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Checking whether PHP is configured according to https://docs.phpunit.de/en/%s/installation.html#configuring-php-for-development + +display_errors = On ... ok +display_startup_errors = On ... ok +error_reporting = -1 ... ok +zend.assertions = 1 ... ok +assert.exception = 1 ... ok +memory_limit = -1 ... ok diff --git a/tests/end-to-end/cli/bootstrap-not-found.phpt b/tests/end-to-end/cli/bootstrap-not-found.phpt new file mode 100644 index 00000000000..855cfcff297 --- /dev/null +++ b/tests/end-to-end/cli/bootstrap-not-found.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test fail on missing bootstrap +--ARGS-- +--no-configuration --bootstrap nonExistingBootstrap.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Cannot open bootstrap script "nonExistingBootstrap.php" diff --git a/tests/end-to-end/cli/child-process-output.phpt b/tests/end-to-end/cli/child-process-output.phpt new file mode 100644 index 00000000000..3624916670f --- /dev/null +++ b/tests/end-to-end/cli/child-process-output.phpt @@ -0,0 +1,26 @@ +--TEST-- +ShutdownHandler does not output when child process exits +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 2 assertions) diff --git a/tests/end-to-end/cli/columns/columns-max.phpt b/tests/end-to-end/cli/columns/columns-max.phpt new file mode 100644 index 00000000000..79a98a724c7 --- /dev/null +++ b/tests/end-to-end/cli/columns/columns-max.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --columns=max ../../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/cli/columns/columns-too-few.phpt b/tests/end-to-end/cli/columns/columns-too-few.phpt new file mode 100644 index 00000000000..2dc69db0d31 --- /dev/null +++ b/tests/end-to-end/cli/columns/columns-too-few.phpt @@ -0,0 +1,27 @@ +--TEST-- +phpunit --columns=1 ../../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Less than 16 columns requested, number of columns set to 16 + +OK, but there were issues! +Tests: 3, Assertions: 3, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/cli/columns/columns.phpt b/tests/end-to-end/cli/columns/columns.phpt new file mode 100644 index 00000000000..e0c417548b2 --- /dev/null +++ b/tests/end-to-end/cli/columns/columns.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --columns=40 ../../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite-all.phpt b/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite-all.phpt new file mode 100644 index 00000000000..2e5a2953b09 --- /dev/null +++ b/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite-all.phpt @@ -0,0 +1,42 @@ +--TEST-- +Tests selected using with "--all" CLI option +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (unit, 1 test) +Test Suite Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest, 1 test) +Test Suite Finished (unit, 1 test) +Test Suite Started (end-to-end, 1 test) +Test Suite Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest::testOne) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest::testOne) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest::testOne) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\EndToEndTest, 1 test) +Test Suite Finished (end-to-end, 1 test) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite.phpt b/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite.phpt new file mode 100644 index 00000000000..09771346f69 --- /dev/null +++ b/tests/end-to-end/cli/configuration-file-based-test-selection/defaultTestSuite.phpt @@ -0,0 +1,33 @@ +--TEST-- +Tests selected using +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (unit, 1 test) +Test Suite Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\DefaultTestSuite\UnitTest, 1 test) +Test Suite Finished (unit, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/configuration-file-based-test-selection/groups-all.phpt b/tests/end-to-end/cli/configuration-file-based-test-selection/groups-all.phpt new file mode 100644 index 00000000000..519ff80e191 --- /dev/null +++ b/tests/end-to-end/cli/configuration-file-based-test-selection/groups-all.phpt @@ -0,0 +1,38 @@ +--TEST-- +Tests selected using with "--all" CLI option +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (default, 2 tests) +Test Suite Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testTwo) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testTwo) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest, 2 tests) +Test Suite Finished (default, 2 tests) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/configuration-file-based-test-selection/groups.phpt b/tests/end-to-end/cli/configuration-file-based-test-selection/groups.phpt new file mode 100644 index 00000000000..107ce7a4968 --- /dev/null +++ b/tests/end-to-end/cli/configuration-file-based-test-selection/groups.phpt @@ -0,0 +1,34 @@ +--TEST-- +Tests selected using +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Prepared (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Passed (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ConfigurationFileBasedTestSelection\Groups\ExampleTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/coverage/coverage-no-tests-when-missing-coverage-driver.phpt b/tests/end-to-end/cli/coverage/coverage-no-tests-when-missing-coverage-driver.phpt new file mode 100644 index 00000000000..49a4a9a327b --- /dev/null +++ b/tests/end-to-end/cli/coverage/coverage-no-tests-when-missing-coverage-driver.phpt @@ -0,0 +1,27 @@ +--TEST-- +Don't run tests when coverage driver is not loaded +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt b/tests/end-to-end/cli/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt new file mode 100644 index 00000000000..b7aa71e1841 --- /dev/null +++ b/tests/end-to-end/cli/coverage/coverage-no-tests-when-wrong-xdebug-mode.phpt @@ -0,0 +1,26 @@ +--TEST-- +Don't run tests when wrong xdebug mode is set +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-deprecation.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-deprecation.phpt new file mode 100644 index 00000000000..23b7264c4bf --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-deprecation.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersDeprecation) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersDeprecation) +Test Triggered Deprecation (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersDeprecation, unknown if issue was triggered in first-party code or third-party code) in %sIssueTest.php:%d +message +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersDeprecation) +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersDeprecation) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-incomplete.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-incomplete.phpt new file mode 100644 index 00000000000..52ecd8ba19d --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-incomplete.phpt @@ -0,0 +1,38 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsIncomplete) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsIncomplete) +Test Marked Incomplete (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsIncomplete) +message +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsIncomplete) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-notice.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-notice.phpt new file mode 100644 index 00000000000..1cd528296a4 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-notice.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersNotice) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersNotice) +Test Triggered Notice (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersNotice) in %sIssueTest.php:%d +message +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersNotice) +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersNotice) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-deprecation.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-deprecation.phpt new file mode 100644 index 00000000000..7ac3dd34953 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-deprecation.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitDeprecation) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitDeprecation) +Test Triggered PHPUnit Deprecation (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitDeprecation) +message +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitDeprecation) +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitDeprecation) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-warning.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-warning.phpt new file mode 100644 index 00000000000..b6ae1c5e952 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-phpunit-warning.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitWarning) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitWarning) +Test Triggered PHPUnit Warning (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitWarning) +message +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitWarning) +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersPhpunitWarning) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-risky.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-risky.phpt new file mode 100644 index 00000000000..422729b06c1 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-risky.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsRisky) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsRisky) +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsRisky) +Test Considered Risky (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsRisky) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsRisky) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-skipped.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-skipped.phpt new file mode 100644 index 00000000000..2475b4d1d24 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-skipped.phpt @@ -0,0 +1,38 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsSkipped) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsSkipped) +Test Skipped (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsSkipped) +message +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatIsSkipped) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-warning.phpt b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-warning.phpt new file mode 100644 index 00000000000..7f11b5f1d01 --- /dev/null +++ b/tests/end-to-end/cli/do-not-fail-on/do-not-fail-on-warning.phpt @@ -0,0 +1,39 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersWarning) +Test Prepared (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersWarning) +Test Triggered Warning (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersWarning) in %sIssueTest.php:%d +message +Test Passed (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersWarning) +Test Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest::testThatTriggersWarning) +Test Suite Finished (PHPUnit\TestFixture\DoNotFailOn\IssueTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/exclude-filter/match.phpt b/tests/end-to-end/cli/exclude-filter/match.phpt new file mode 100644 index 00000000000..c78875601bf --- /dev/null +++ b/tests/end-to-end/cli/exclude-filter/match.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --exclude-filter testThree ../../_files/groups/tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (2 tests) +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/exclude-multiple-test-suites.phpt b/tests/end-to-end/cli/exclude-multiple-test-suites.phpt new file mode 100644 index 00000000000..eb31b2259ac --- /dev/null +++ b/tests/end-to-end/cli/exclude-multiple-test-suites.phpt @@ -0,0 +1,25 @@ +--TEST-- +Exclude multiple test suites using --exclude-testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/exclude-single-test-suite.phpt b/tests/end-to-end/cli/exclude-single-test-suite.phpt new file mode 100644 index 00000000000..9b33cbfab7c --- /dev/null +++ b/tests/end-to-end/cli/exclude-single-test-suite.phpt @@ -0,0 +1,35 @@ +--TEST-- +Exclude single test suite using --exclude-testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (end-to-end, 1 test) +Test Suite Started (PHPUnit\TestFixture\BarTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BarTest, 1 test) +Test Suite Finished (end-to-end, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-deprecation-and-fail-on-deprecation.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-deprecation-and-fail-on-deprecation.phpt new file mode 100644 index 00000000000..36cdc936011 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-deprecation-and-fail-on-deprecation.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-deprecation and --do-not-fail-on-deprecation cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-and-fail-on-empty-test-suite.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-and-fail-on-empty-test-suite.phpt new file mode 100644 index 00000000000..8724ed7bcc2 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-and-fail-on-empty-test-suite.phpt @@ -0,0 +1,20 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-empty-test-suite and --do-not-fail-on-empty-test-suite cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-by-default.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-by-default.phpt new file mode 100644 index 00000000000..2a0dfae0479 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-empty-test-suite-by-default.phpt @@ -0,0 +1,26 @@ +--TEST-- +Test Runner exits with shell exit code indicating success by default when no tests were run +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-incomplete-and-fail-on-incomplete.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-incomplete-and-fail-on-incomplete.phpt new file mode 100644 index 00000000000..80739417eb2 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-incomplete-and-fail-on-incomplete.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-incomplete and --do-not-fail-on-incomplete cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-notice-and-fail-on-notice.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-notice-and-fail-on-notice.phpt new file mode 100644 index 00000000000..e1be85820b0 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-notice-and-fail-on-notice.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-notice and --do-not-fail-on-notice cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-phpunit-deprecation-and-fail-on-phpunit-deprecation.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-phpunit-deprecation-and-fail-on-phpunit-deprecation.phpt new file mode 100644 index 00000000000..f26a473539d --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-phpunit-deprecation-and-fail-on-phpunit-deprecation.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-phpunit-deprecation and --do-not-fail-on-phpunit-deprecation cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-risky-and-fail-on-risky.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-risky-and-fail-on-risky.phpt new file mode 100644 index 00000000000..d5386a8b939 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-risky-and-fail-on-risky.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-risky and --do-not-fail-on-risky cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-skipped-and-fail-on-skipped.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-skipped-and-fail-on-skipped.phpt new file mode 100644 index 00000000000..596c1268e64 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-skipped-and-fail-on-skipped.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-skipped and --do-not-fail-on-skipped cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/do-not-fail-on-warning-and-fail-on-warning.phpt b/tests/end-to-end/cli/fail-on/do-not-fail-on-warning-and-fail-on-warning.phpt new file mode 100644 index 00000000000..f0859f85279 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/do-not-fail-on-warning-and-fail-on-warning.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --fail-on-warning and --do-not-fail-on-warning cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-deprecation-and-do-not-fail-on-deprecation.phpt b/tests/end-to-end/cli/fail-on/fail-on-deprecation-and-do-not-fail-on-deprecation.phpt new file mode 100644 index 00000000000..83eeca34504 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-deprecation-and-do-not-fail-on-deprecation.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-deprecation and --fail-on-deprecation cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-deprecation-output.phpt b/tests/end-to-end/cli/fail-on/fail-on-deprecation-output.phpt new file mode 100644 index 00000000000..811237e3e32 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-deprecation-output.phpt @@ -0,0 +1,38 @@ +--TEST-- +Details for deprecations are displayed when --fail-on-deprecation is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +D.D 3 / 3 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit deprecation: + +1) PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree +message + +%sDeprecationTest.php:%d + +-- + +1 test triggered 1 deprecation: + +1) %sDeprecationTest.php:%d +message + +OK, but there were issues! +Tests: 3, Assertions: 3, Deprecations: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/cli/fail-on/fail-on-deprecation.phpt b/tests/end-to-end/cli/fail-on/fail-on-deprecation.phpt new file mode 100644 index 00000000000..6f182f63c96 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-deprecation.phpt @@ -0,0 +1,42 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test triggered a deprecation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Triggered PHPUnit Deprecation (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite-and-do-not-fail-on-empty-test-suite.phpt b/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite-and-do-not-fail-on-empty-test-suite.phpt new file mode 100644 index 00000000000..17e8c8af92f --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite-and-do-not-fail-on-empty-test-suite.phpt @@ -0,0 +1,20 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-empty-test-suite and --fail-on-empty-test-suite cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite.phpt b/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite.phpt new file mode 100644 index 00000000000..e900ce18e87 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-empty-test-suite.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when no tests were run and --fail-on-empty-test-suite option is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-incomplete-and-do-not-fail-on-incomplete.phpt b/tests/end-to-end/cli/fail-on/fail-on-incomplete-and-do-not-fail-on-incomplete.phpt new file mode 100644 index 00000000000..8e15c5dc0e8 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-incomplete-and-do-not-fail-on-incomplete.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-incomplete and --fail-on-incomplete cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-incomplete-output.phpt b/tests/end-to-end/cli/fail-on/fail-on-incomplete-output.phpt new file mode 100644 index 00000000000..e22c73e8ea1 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-incomplete-output.phpt @@ -0,0 +1,30 @@ +--TEST-- +Details for incomplete tests are displayed when --fail-on-incomplete is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +I. 2 / 2 (100%) + +Time: %s, Memory: %s + +There was 1 incomplete test: + +1) PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne +message + +%sIncompleteTest.php:%d + +OK, but there were issues! +Tests: 2, Assertions: 1, Incomplete: 1. diff --git a/tests/end-to-end/cli/fail-on/fail-on-incomplete.phpt b/tests/end-to-end/cli/fail-on/fail-on-incomplete.phpt new file mode 100644 index 00000000000..a80fb40a1d4 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-incomplete.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test was marked incomplete +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Marked Incomplete (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-notice-and-do-not-fail-on-notice.phpt b/tests/end-to-end/cli/fail-on/fail-on-notice-and-do-not-fail-on-notice.phpt new file mode 100644 index 00000000000..53f63fb84a7 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-notice-and-do-not-fail-on-notice.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-notice and --fail-on-notice cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-notice-output.phpt b/tests/end-to-end/cli/fail-on/fail-on-notice-output.phpt new file mode 100644 index 00000000000..1662950e39f --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-notice-output.phpt @@ -0,0 +1,28 @@ +--TEST-- +Details for notices are displayed when --fail-on-notice is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +N. 2 / 2 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 notice: + +1) %sNoticeTest.php:%d +message + +OK, but there were issues! +Tests: 2, Assertions: 2, Notices: 1. diff --git a/tests/end-to-end/cli/fail-on/fail-on-notice.phpt b/tests/end-to-end/cli/fail-on/fail-on-notice.phpt new file mode 100644 index 00000000000..f9c1de85831 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-notice.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test triggered a notice +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Triggered Notice (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation-and-do-not-fail-on-phpunit-deprecation.phpt b/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation-and-do-not-fail-on-phpunit-deprecation.phpt new file mode 100644 index 00000000000..d350818bd7e --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation-and-do-not-fail-on-phpunit-deprecation.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-phpunit-deprecation and --fail-on-phpunit-deprecation cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation.phpt b/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation.phpt new file mode 100644 index 00000000000..e7bbf6b3e0a --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-phpunit-deprecation.phpt @@ -0,0 +1,42 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test triggered a PHPUnit deprecation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Triggered PHPUnit Deprecation (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-phpunit-notice.phpt b/tests/end-to-end/cli/fail-on/fail-on-phpunit-notice.phpt new file mode 100644 index 00000000000..e4ffc139a22 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-phpunit-notice.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test triggered a PHPUnit notice +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testOne) +Test Triggered PHPUnit Notice (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testOne) +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\PhpunitNoticeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-risky-and-do-not-fail-on-risky.phpt b/tests/end-to-end/cli/fail-on/fail-on-risky-and-do-not-fail-on-risky.phpt new file mode 100644 index 00000000000..a4cf71033e8 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-risky-and-do-not-fail-on-risky.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-risky and --fail-on-risky cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-risky.phpt b/tests/end-to-end/cli/fail-on/fail-on-risky.phpt new file mode 100644 index 00000000000..d7323df117a --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-risky.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test was considered risky +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-skipped-and-do-not-fail-on-skipped.phpt b/tests/end-to-end/cli/fail-on/fail-on-skipped-and-do-not-fail-on-skipped.phpt new file mode 100644 index 00000000000..fded7ee858c --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-skipped-and-do-not-fail-on-skipped.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-skipped and --fail-on-skipped cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-skipped-output.phpt b/tests/end-to-end/cli/fail-on/fail-on-skipped-output.phpt new file mode 100644 index 00000000000..4e5155df1f8 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-skipped-output.phpt @@ -0,0 +1,28 @@ +--TEST-- +Details for skipped tests are displayed when --fail-on-skipped is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +S. 2 / 2 (100%) + +Time: %s, Memory: %s + +There was 1 skipped test: + +1) PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne +message + +OK, but some tests were skipped! +Tests: 2, Assertions: 1, Skipped: 1. diff --git a/tests/end-to-end/cli/fail-on/fail-on-skipped.phpt b/tests/end-to-end/cli/fail-on/fail-on-skipped.phpt new file mode 100644 index 00000000000..8978243ea19 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-skipped.phpt @@ -0,0 +1,35 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one test was skipped +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Skipped (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/fail-on/fail-on-warning-and-do-not-fail-on-warning.phpt b/tests/end-to-end/cli/fail-on/fail-on-warning-and-do-not-fail-on-warning.phpt new file mode 100644 index 00000000000..8dce24ea17c --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-warning-and-do-not-fail-on-warning.phpt @@ -0,0 +1,18 @@ +--TEST-- +todo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +%A +Test Runner Triggered Warning (Options --do-not-fail-on-warning and --fail-on-warning cannot be used together) +%A diff --git a/tests/end-to-end/cli/fail-on/fail-on-warning-output.phpt b/tests/end-to-end/cli/fail-on/fail-on-warning-output.phpt new file mode 100644 index 00000000000..8513c5efc6d --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-warning-output.phpt @@ -0,0 +1,28 @@ +--TEST-- +Details for warnings are displayed when --fail-on-warning is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +W. 2 / 2 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 warning: + +1) %sWarningTest.php:%d +message + +OK, but there were issues! +Tests: 2, Assertions: 2, Warnings: 1. diff --git a/tests/end-to-end/cli/fail-on/fail-on-warning.phpt b/tests/end-to-end/cli/fail-on/fail-on-warning.phpt new file mode 100644 index 00000000000..0d3c6783723 --- /dev/null +++ b/tests/end-to-end/cli/fail-on/fail-on-warning.phpt @@ -0,0 +1,36 @@ +--TEST-- +Test Runner exits with shell exit code indicating failure when all tests are successful but at least one warning was triggered +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Triggered Warning (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testTwo) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/failure-reverse-list.phpt b/tests/end-to-end/cli/failure-reverse-list.phpt new file mode 100644 index 00000000000..15898e27cd9 --- /dev/null +++ b/tests/end-to-end/cli/failure-reverse-list.phpt @@ -0,0 +1,143 @@ +--TEST-- +phpunit --reverse-list ../../_files/FailureTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +FFFFFFFFFFFFF 13 / 13 (100%) + +Time: %s, Memory: %s + +There were 13 failures: + +1) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormatFile +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-FOO ++...BAR... + +%s:%d + +2) PHPUnit\TestFixture\FailureTest::testAssertFloatSameFloat +message +Failed asserting that 1.5 is identical to 1.0. + +%s:%d + +3) PHPUnit\TestFixture\FailureTest::testAssertObjectSameNull +message +Failed asserting that null is identical to an object of class "stdClass". + +%s:%d + +4) PHPUnit\TestFixture\FailureTest::testAssertObjectSameObject +message +Failed asserting that two variables reference the same object. + +%s:%d + +5) PHPUnit\TestFixture\FailureTest::testAssertTextSameText +message +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%d + +6) PHPUnit\TestFixture\FailureTest::testAssertNumericEqualsNumeric +message +Failed asserting that 2 matches expected 1. + +%s:%d + +7) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormat +message +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-*%s* ++** + +%s:%d + +8) PHPUnit\TestFixture\FailureTest::testAssertTextEqualsText +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ + 'foo\n +-bar\n ++baz\n + ' + +%s:%d + +9) PHPUnit\TestFixture\FailureTest::testAssertStringEqualsString +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%d + +10) PHPUnit\TestFixture\FailureTest::testAssertNullEqualsString +message +Failed asserting that 'bar' matches expected null. + +%s:%d + +11) PHPUnit\TestFixture\FailureTest::testAssertObjectEqualsObject +message +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 'foo' => 'bar' ++ 'bar' => 'foo' + ) + +%s:%d + +12) PHPUnit\TestFixture\FailureTest::testAssertIntegerEqualsInteger +message +Failed asserting that 2 matches expected 1. + +%s:%d + +13) PHPUnit\TestFixture\FailureTest::testAssertArrayEqualsArray +message +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1 ++ 0 => 2 + ) + +%s:%d + +FAILURES! +Tests: 13, Assertions: 15, Failures: 13. diff --git a/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-disabled.phpt b/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-disabled.phpt new file mode 100644 index 00000000000..baf8b1113d1 --- /dev/null +++ b/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-disabled.phpt @@ -0,0 +1,84 @@ +--TEST-- +phpunit --configuration ../../_files/filter-error-handler/filter-disabled.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s%efilter-disabled.xml + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 2 warnings: + +1) %s%esrc%eSourceClass.php:23 +warning + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +2) %s%evendor%eVendorClass.php:10 +warning + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +-- + +1 test triggered 2 notices: + +1) %s%esrc%eSourceClass.php:22 +notice + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +2) %s%evendor%eVendorClass.php:9 +notice + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +-- + +1 test triggered 2 deprecations: + +1) %s%esrc%eSourceClass.php:21 +deprecation + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +2) %s%evendor%eVendorClass.php:8 +deprecation + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 2, Deprecations: 2, Notices: 2. diff --git a/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-enabled.phpt b/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-enabled.phpt new file mode 100644 index 00000000000..06b9a2f53d6 --- /dev/null +++ b/tests/end-to-end/cli/filter-error-handler/filter-for-error-handler-events-enabled.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --configuration ../../_files/filter-error-handler/filter-enabled.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s%efilter-enabled.xml + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 warning: + +1) %s%esrc%eSourceClass.php:23 +warning + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +-- + +1 test triggered 1 notice: + +1) %s%esrc%eSourceClass.php:22 +notice + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +-- + +1 test triggered 1 deprecation: + +1) %s%esrc%eSourceClass.php:21 +deprecation + +Triggered by: + +* PHPUnit\TestFixture\FilterErrorHandler\SourceClassTest::testSomething + %s%etests%eSourceClassTest.php:16 + +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1, Deprecations: 1, Notices: 1. diff --git a/tests/end-to-end/cli/filter/filter-class-match-argument.phpt b/tests/end-to-end/cli/filter/filter-class-match-argument.phpt new file mode 100644 index 00000000000..0f8f07a1750 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-class-match-argument.phpt @@ -0,0 +1,40 @@ +--TEST-- +phpunit --filter FooTest tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (3 tests) +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-class-match-configuration.phpt b/tests/end-to-end/cli/filter/filter-class-match-configuration.phpt new file mode 100644 index 00000000000..17e98448355 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-class-match-configuration.phpt @@ -0,0 +1,44 @@ +--TEST-- +phpunit --filter FooTest +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (3 tests) +Test Runner Execution Started (3 tests) +Test Suite Started (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 3 tests) +Test Suite Started (default, 3 tests) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 3 tests) +Test Suite Finished (default, 3 tests) +Test Suite Finished (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-class-nomatch-argument.phpt b/tests/end-to-end/cli/filter/filter-class-nomatch-argument.phpt new file mode 100644 index 00000000000..be71939651b --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-class-nomatch-argument.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --filter BarTest tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-class-nomatch-configuration.phpt b/tests/end-to-end/cli/filter/filter-class-nomatch-configuration.phpt new file mode 100644 index 00000000000..23a7967a205 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-class-nomatch-configuration.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --filter BarTest +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-classname-and-range.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-classname-and-range.phpt new file mode 100644 index 00000000000..0e1d538a5a5 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-classname-and-range.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter DataProviderFilterTest#1-3 ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-number.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-number.phpt new file mode 100644 index 00000000000..f38daf08f40 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-number.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter testTrue#3 ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-only-range.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-range.phpt new file mode 100644 index 00000000000..3ae50c2b86d --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-range.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter \#1-3 ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-only-regexp.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-regexp.phpt new file mode 100644 index 00000000000..e086d3aca04 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-regexp.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter @false.* ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-only-string.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-string.phpt new file mode 100644 index 00000000000..57e7b5b0491 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-only-string.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter @false\ test ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-number-key.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-number-key.phpt new file mode 100644 index 00000000000..0d0a688d861 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-number-key.phpt @@ -0,0 +1,72 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/6364 +--FILE-- + ['pipe', 'w'], + ], + $pipes, +); + +$stdout = stream_get_contents($pipes[1]); +fclose($pipes[1]); +proc_close($process); + +if (preg_match("/##teamcity\\[testStarted name='testTrue with data set #1' locationHint='([^']+)'/", $stdout, $matches) !== 1) { + echo "Failed to find locationHint.\n"; + echo $stdout; + + return 0; +} + +if (preg_match('#php_qn://(?:[A-Z]:)?[^:]*::\\\\(.*)#', $matches[1], $locationHintMatches) !== 1) { + echo "Failed to parse locationHint.\n"; + echo $matches[1]; + + return 0; +} + +// Simulate how PHPStorm runs an individual numbered test case +$_SERVER['argv'][] = '--do-not-cache-result'; +$_SERVER['argv'][] = '--no-configuration'; +$_SERVER['argv'][] = '--filter'; +$_SERVER['argv'][] = '/' . preg_quote($locationHintMatches[1], '/') . '$/'; +$_SERVER['argv'][] = '--test-suffix'; +$_SERVER['argv'][] = 'DataProviderFilterTest.php'; +$_SERVER['argv'][] = __DIR__ . '/../../../_files'; +$_SERVER['argv'][] = '--teamcity'; + +require_once __DIR__ . '/../../../bootstrap.php'; +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s + +##teamcity[testCount count='1' flowId='%s'] +##teamcity[testSuiteStarted name='CLI Arguments' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\DataProviderFilterTest' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest' flowId='%d'] +##teamcity[testSuiteStarted name='testTrue' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest::testTrue' flowId='%d'] +##teamcity[testStarted name='testTrue with data set #1' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest::testTrue with data set #1' flowId='%d'] +##teamcity[testFinished name='testTrue with data set #1' duration='%s' flowId='%d'] +##teamcity[testSuiteFinished name='testTrue' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\DataProviderFilterTest' flowId='%d'] +##teamcity[testSuiteFinished name='CLI Arguments' flowId='%d'] +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-string-key.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-string-key.phpt new file mode 100644 index 00000000000..c15fce6c5da --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-phpstorm-regex-string-key.phpt @@ -0,0 +1,72 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/6364 +--FILE-- + ['pipe', 'w'], + ], + $pipes, +); + +$stdout = stream_get_contents($pipes[1]); +fclose($pipes[1]); +proc_close($process); + +if (preg_match("/##teamcity\\[testStarted name='testFalse with data set \"false test\"' locationHint='([^']+)'/", $stdout, $matches) !== 1) { + echo "Failed to find locationHint.\n"; + echo $stdout; + + return 0; +} + +if (preg_match('#php_qn://(?:[A-Z]:)?[^:]*::\\\\(.*)#', $matches[1], $locationHintMatches) !== 1) { + echo "Failed to parse locationHint.\n"; + echo $matches[1]; + + return 0; +} + +// Simulate how PHPStorm runs an individual named test case +$_SERVER['argv'][] = '--do-not-cache-result'; +$_SERVER['argv'][] = '--no-configuration'; +$_SERVER['argv'][] = '--filter'; +$_SERVER['argv'][] = '/' . preg_quote($locationHintMatches[1], '/') . '$/'; +$_SERVER['argv'][] = '--test-suffix'; +$_SERVER['argv'][] = 'DataProviderFilterTest.php'; +$_SERVER['argv'][] = __DIR__ . '/../../../_files'; +$_SERVER['argv'][] = '--teamcity'; + +require_once __DIR__ . '/../../../bootstrap.php'; +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s + +##teamcity[testCount count='1' flowId='%s'] +##teamcity[testSuiteStarted name='CLI Arguments' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\DataProviderFilterTest' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest' flowId='%d'] +##teamcity[testSuiteStarted name='testFalse' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest::testFalse' flowId='%d'] +##teamcity[testStarted name='testFalse with data set "false test"' locationHint='php_qn://%sDataProviderFilterTest.php::\PHPUnit\TestFixture\DataProviderFilterTest::testFalse with data set "false test"' flowId='%d'] +##teamcity[testFinished name='testFalse with data set "false test"' duration='%s' flowId='%d'] +##teamcity[testSuiteFinished name='testFalse' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\DataProviderFilterTest' flowId='%d'] +##teamcity[testSuiteFinished name='CLI Arguments' flowId='%d'] +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-range.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-range.phpt new file mode 100644 index 00000000000..ed181d47662 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-range.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter testTrue#1-3 ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-regexp.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-regexp.phpt new file mode 100644 index 00000000000..d0a734f8880 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-regexp.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter testFalse@false.* ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/cli/filter/filter-dataprovider-by-string.phpt b/tests/end-to-end/cli/filter/filter-dataprovider-by-string.phpt new file mode 100644 index 00000000000..cf3b79e8cf8 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-dataprovider-by-string.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter testFalse@false\ test ../../_files/DataProviderFilterTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-method-case-insensitive.phpt b/tests/end-to-end/cli/filter/filter-method-case-insensitive.phpt new file mode 100644 index 00000000000..054d468d1af --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-case-insensitive.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --filter /balanceIsInitiallyZero/i ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/cli/filter/filter-method-case-sensitive-no-result.phpt b/tests/end-to-end/cli/filter/filter-method-case-sensitive-no-result.phpt new file mode 100644 index 00000000000..dbaa062d563 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-case-sensitive-no-result.phpt @@ -0,0 +1,18 @@ +--TEST-- +phpunit --filter balanceIsInitiallyZero ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +No tests executed! diff --git a/tests/end-to-end/cli/filter/filter-method-match-argument.phpt b/tests/end-to-end/cli/filter/filter-method-match-argument.phpt new file mode 100644 index 00000000000..8fc0f1b4a58 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-match-argument.phpt @@ -0,0 +1,32 @@ +--TEST-- +phpunit --filter testOne tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-method-match-configuration.phpt b/tests/end-to-end/cli/filter/filter-method-match-configuration.phpt new file mode 100644 index 00000000000..f74ff0d5d68 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-match-configuration.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --filter testOne +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-method-nomatch-argument.phpt b/tests/end-to-end/cli/filter/filter-method-nomatch-argument.phpt new file mode 100644 index 00000000000..cd052a99bd3 --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-nomatch-argument.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --filter testFoo tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/filter/filter-method-nomatch-configuration.phpt b/tests/end-to-end/cli/filter/filter-method-nomatch-configuration.phpt new file mode 100644 index 00000000000..f1b8168a91f --- /dev/null +++ b/tests/end-to-end/cli/filter/filter-method-nomatch-configuration.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --filter testFoo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/generate-configuration.phpt b/tests/end-to-end/cli/generate-configuration.phpt new file mode 100644 index 00000000000..4909f8f360f --- /dev/null +++ b/tests/end-to-end/cli/generate-configuration.phpt @@ -0,0 +1,24 @@ +--TEST-- +phpunit --generate-configuration +--STDIN-- + + + + +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Generating phpunit.xml in %s + +Bootstrap script (relative to path shown above; default: vendor/autoload.php): Tests directory (relative to path shown above; default: tests): Source directory (relative to path shown above; default: src): Cache directory (relative to path shown above; default: .phpunit.cache): +Generated phpunit.xml in %s. +Make sure to exclude the .phpunit.cache directory from version control. diff --git a/tests/end-to-end/cli/group/covers-class.phpt b/tests/end-to-end/cli/group/covers-class.phpt new file mode 100644 index 00000000000..a573705ec4a --- /dev/null +++ b/tests/end-to-end/cli/group/covers-class.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --covers PHPUnit\TestFixture\AttributeBasedFiltering\Foo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (5 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest::testOne) +Test Passed (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest::testOne) +Test Finished (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\AttributeBasedFiltering\CoversClassTest, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/covers-function.phpt b/tests/end-to-end/cli/group/covers-function.phpt new file mode 100644 index 00000000000..44b894c98b2 --- /dev/null +++ b/tests/end-to-end/cli/group/covers-function.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --covers PHPUnit\TestFixture\AttributeBasedFiltering\f +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (5 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest::testOne) +Test Prepared (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest::testOne) +Test Passed (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest::testOne) +Test Finished (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\AttributeBasedFiltering\CoversFunctionTest, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/exclude-group-argument.phpt b/tests/end-to-end/cli/group/exclude-group-argument.phpt new file mode 100644 index 00000000000..81e0027bed9 --- /dev/null +++ b/tests/end-to-end/cli/group/exclude-group-argument.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --exclude-group one,two tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/exclude-group-configuration.phpt b/tests/end-to-end/cli/group/exclude-group-configuration.phpt new file mode 100644 index 00000000000..cd3cb8f911b --- /dev/null +++ b/tests/end-to-end/cli/group/exclude-group-configuration.phpt @@ -0,0 +1,38 @@ +--TEST-- +phpunit --exclude-group one,two +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/group-argument.phpt b/tests/end-to-end/cli/group/group-argument.phpt new file mode 100644 index 00000000000..8977194b861 --- /dev/null +++ b/tests/end-to-end/cli/group/group-argument.phpt @@ -0,0 +1,32 @@ +--TEST-- +phpunit --group one tests/FooTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/group-configuration.phpt b/tests/end-to-end/cli/group/group-configuration.phpt new file mode 100644 index 00000000000..f2dfaf744fc --- /dev/null +++ b/tests/end-to-end/cli/group/group-configuration.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --group one +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\Groups\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Groups\FooTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%s%etests%eend-to-end%e_files%egroups%ephpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/requires-php-extension.phpt b/tests/end-to-end/cli/group/requires-php-extension.phpt new file mode 100644 index 00000000000..4d2e66f33c2 --- /dev/null +++ b/tests/end-to-end/cli/group/requires-php-extension.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --requires-php-extension standard +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (5 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest::testOne) +Test Prepared (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest::testOne) +Test Passed (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest::testOne) +Test Finished (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\AttributeBasedFiltering\RequiresPhpExtensionTest, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/uses-class.phpt b/tests/end-to-end/cli/group/uses-class.phpt new file mode 100644 index 00000000000..a2631cdf3b0 --- /dev/null +++ b/tests/end-to-end/cli/group/uses-class.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --uses PHPUnit\TestFixture\AttributeBasedFiltering\Foo +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (5 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest::testOne) +Test Prepared (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest::testOne) +Test Passed (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest::testOne) +Test Finished (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\AttributeBasedFiltering\UsesTest, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/group/uses-function.phpt b/tests/end-to-end/cli/group/uses-function.phpt new file mode 100644 index 00000000000..2b71c3956bb --- /dev/null +++ b/tests/end-to-end/cli/group/uses-function.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit --covers PHPUnit\TestFixture\AttributeBasedFiltering\f +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (5 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest::testOne) +Test Prepared (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest::testOne) +Test Passed (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest::testOne) +Test Finished (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\AttributeBasedFiltering\UsesFunctionTest, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/help/help-color.phpt b/tests/end-to-end/cli/help/help-color.phpt new file mode 100644 index 00000000000..dfe3fcc2798 --- /dev/null +++ b/tests/end-to-end/cli/help/help-color.phpt @@ -0,0 +1,13 @@ +--TEST-- +phpunit --help +--ARGS-- +--no-configuration --help +--FILE-- +generate(); +--EXPECTF_EXTERNAL-- +../../_files/output-cli-help-color.txt diff --git a/tests/end-to-end/cli/help/help.phpt b/tests/end-to-end/cli/help/help.phpt new file mode 100644 index 00000000000..d430f0051f8 --- /dev/null +++ b/tests/end-to-end/cli/help/help.phpt @@ -0,0 +1,10 @@ +--TEST-- +phpunit +--ARGS-- +--no-configuration --columns=80 +--FILE-- +run($_SERVER['argv']); +--EXPECTF_EXTERNAL-- +../../_files/output-cli-usage.txt diff --git a/tests/end-to-end/cli/help/help2.phpt b/tests/end-to-end/cli/help/help2.phpt new file mode 100644 index 00000000000..35879615a2f --- /dev/null +++ b/tests/end-to-end/cli/help/help2.phpt @@ -0,0 +1,10 @@ +--TEST-- +phpunit --help +--ARGS-- +--no-configuration --columns=80 --help +--FILE-- +run($_SERVER['argv']); +--EXPECTF_EXTERNAL-- +../../_files/output-cli-usage.txt diff --git a/tests/end-to-end/cli/include-multiple-test-suites.phpt b/tests/end-to-end/cli/include-multiple-test-suites.phpt new file mode 100644 index 00000000000..97bea961728 --- /dev/null +++ b/tests/end-to-end/cli/include-multiple-test-suites.phpt @@ -0,0 +1,43 @@ +--TEST-- +Include multiple test suite using --testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (unit, 1 test) +Test Suite Started (PHPUnit\TestFixture\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\FooTest, 1 test) +Test Suite Finished (unit, 1 test) +Test Suite Started (end-to-end, 1 test) +Test Suite Started (PHPUnit\TestFixture\BarTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BarTest, 1 test) +Test Suite Finished (end-to-end, 1 test) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/include-single-test-suite.phpt b/tests/end-to-end/cli/include-single-test-suite.phpt new file mode 100644 index 00000000000..88cacb70e1c --- /dev/null +++ b/tests/end-to-end/cli/include-single-test-suite.phpt @@ -0,0 +1,35 @@ +--TEST-- +Include single test suite using --testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (end-to-end, 1 test) +Test Suite Started (PHPUnit\TestFixture\BarTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BarTest, 1 test) +Test Suite Finished (end-to-end, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/list-suites/default-test-suite-all.phpt b/tests/end-to-end/cli/list-suites/default-test-suite-all.phpt new file mode 100644 index 00000000000..f71f93b8662 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/default-test-suite-all.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/default-test-suite.xml --list-suites --all +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/default-test-suite.phpt b/tests/end-to-end/cli/list-suites/default-test-suite.phpt new file mode 100644 index 00000000000..5aa8b35de6b --- /dev/null +++ b/tests/end-to-end/cli/list-suites/default-test-suite.phpt @@ -0,0 +1,17 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/default-test-suite.xml --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test suite: + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/happy-path.phpt b/tests/end-to-end/cli/list-suites/happy-path.phpt new file mode 100644 index 00000000000..82c006799d8 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/happy-path.phpt @@ -0,0 +1,18 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/phpunit.xml --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-exclude-groups-cli.phpt b/tests/end-to-end/cli/list-suites/warning-exclude-groups-cli.phpt new file mode 100644 index 00000000000..c1f2dc76849 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-exclude-groups-cli.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/phpunit.xml --exclude-group default --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --exclude-group (CLI) and (XML) options cannot be combined with --list-suites, --exclude-group and are ignored + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-exclude-groups-xml.phpt b/tests/end-to-end/cli/list-suites/warning-exclude-groups-xml.phpt new file mode 100644 index 00000000000..afcd824bab9 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-exclude-groups-xml.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/exclude-group.xml --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --exclude-group (CLI) and (XML) options cannot be combined with --list-suites, --exclude-group and are ignored + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-filter.phpt b/tests/end-to-end/cli/list-suites/warning-filter.phpt new file mode 100644 index 00000000000..15f993a0c65 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-filter.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/phpunit.xml --filter FooTest --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --filter and --list-suites options cannot be combined, --filter is ignored + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-include-groups-cli.phpt b/tests/end-to-end/cli/list-suites/warning-include-groups-cli.phpt new file mode 100644 index 00000000000..5d9b556c0e3 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-include-groups-cli.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/phpunit.xml --group default --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --group (CLI) and (XML) options cannot be combined with --list-suites, --group and are ignored + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-include-groups-xml.phpt b/tests/end-to-end/cli/list-suites/warning-include-groups-xml.phpt new file mode 100644 index 00000000000..e22262cfd85 --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-include-groups-xml.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/include-group.xml --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --group (CLI) and (XML) options cannot be combined with --list-suites, --group and are ignored + +Available test suites: + - end-to-end (1 test) + - unit (1 test) diff --git a/tests/end-to-end/cli/list-suites/warning-testsuite.phpt b/tests/end-to-end/cli/list-suites/warning-testsuite.phpt new file mode 100644 index 00000000000..6c39e1ed63c --- /dev/null +++ b/tests/end-to-end/cli/list-suites/warning-testsuite.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --configuration ../_files/multiple-testsuites/phpunit.xml --testsuite unit --list-suites +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The --testsuite and --list-suites options cannot be combined, --testsuite is ignored + +Available test suite: + - unit (1 test) diff --git a/tests/end-to-end/cli/list-test-files/list-test-files-exclude-group.phpt b/tests/end-to-end/cli/list-test-files/list-test-files-exclude-group.phpt new file mode 100644 index 00000000000..1f76ba5bdf3 --- /dev/null +++ b/tests/end-to-end/cli/list-test-files/list-test-files-exclude-group.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --list-test-files --exclude-group one ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test files: + - %slisting-tests-and-groups%sExampleExtendingAbstractTest.php + - %slisting-tests-and-groups%sExampleTest.php + - %slisting-tests-and-groups%sexample.phpt diff --git a/tests/end-to-end/cli/list-test-files/list-test-files-group.phpt b/tests/end-to-end/cli/list-test-files/list-test-files-group.phpt new file mode 100644 index 00000000000..851eff96586 --- /dev/null +++ b/tests/end-to-end/cli/list-test-files/list-test-files-group.phpt @@ -0,0 +1,17 @@ +--TEST-- +phpunit --list-test-files --group one ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test files: + - %slisting-tests-and-groups%sExampleTest.php diff --git a/tests/end-to-end/cli/list-test-files/list-test-files.phpt b/tests/end-to-end/cli/list-test-files/list-test-files.phpt new file mode 100644 index 00000000000..5b92fad3d44 --- /dev/null +++ b/tests/end-to-end/cli/list-test-files/list-test-files.phpt @@ -0,0 +1,17 @@ +--TEST-- +phpunit --list-test-files ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test files: + - %slisting-tests-and-groups%sExampleExtendingAbstractTest.php + - %slisting-tests-and-groups%sExampleTest.php + - %slisting-tests-and-groups%sexample.phpt diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-filter.phpt new file mode 100644 index 00000000000..89827356532 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-filter.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --exclude-filter testOne --list-groups ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test groups: + - 3 (1 test) + - two (1 test) diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-group.phpt new file mode 100644 index 00000000000..83f38e04a7e --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-exclude-group.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --exclude-group one --list-groups ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test groups: + - 3 (1 test) + - abstract-one (1 test) + - default (1 test) + - two (1 test) diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-filter.phpt new file mode 100644 index 00000000000..89827356532 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-filter.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --exclude-filter testOne --list-groups ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test groups: + - 3 (1 test) + - two (1 test) diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-group.phpt new file mode 100644 index 00000000000..483cf202b35 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-groups-include-group.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --group one --list-groups ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test group: + - one (1 test) diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-groups.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-groups.phpt new file mode 100644 index 00000000000..707eaa102c5 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-groups.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --list-groups ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test groups: + - 3 (1 test) + - abstract-one (1 test) + - default (1 test) + - one (1 test) + - two (1 test) diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-filter.phpt new file mode 100644 index 00000000000..80fcfb60c8e --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-filter.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --exclude-filter testOne --list-tests ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available tests: + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testTwo + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testThree diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-group.phpt new file mode 100644 index 00000000000..4e4ca2d7464 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-exclude-group.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --exclude-group one --list-tests ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available tests: + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleExtendingAbstractTest::testOne + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testTwo + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testThree + - %sexample.phpt diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-filter.phpt new file mode 100644 index 00000000000..1ee4053afc6 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-filter.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit --filter testOne --list-tests ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available tests: + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleExtendingAbstractTest::testOne + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testOne diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-group.phpt new file mode 100644 index 00000000000..6e32349f377 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-include-group.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --group one --list-tests ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test: + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testOne diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-filter.phpt new file mode 100644 index 00000000000..00546a2c6ff --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-filter.phpt @@ -0,0 +1,35 @@ +--TEST-- +phpunit --exclude-filter testOne --list-tests-xml php://stdout ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + + + + + + + + + + + + + + + + + +%A diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-group.phpt new file mode 100644 index 00000000000..2140b090194 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-exclude-group.phpt @@ -0,0 +1,42 @@ +--TEST-- +phpunit --exclude-group one --list-tests-xml php://stdout ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + + + + + + + + + + + + + + + + + + + + + + + + +%A diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-filter.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-filter.phpt new file mode 100644 index 00000000000..74334ffa1b9 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-filter.phpt @@ -0,0 +1,37 @@ +--TEST-- +phpunit --filter testOne --list-tests-xml php://stdout ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + + + + + + + + + + + + + + + + + + + +%A diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-group.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-group.phpt new file mode 100644 index 00000000000..57ca8004d31 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml-include-group.phpt @@ -0,0 +1,31 @@ +--TEST-- +phpunit --group one --list-tests-xml php://stdout ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + + + + + + + + + + + + + +%A diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml.phpt new file mode 100644 index 00000000000..747742612b9 --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests-xml.phpt @@ -0,0 +1,45 @@ +--TEST-- +phpunit --no-output --list-tests-xml php://stdout ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + + + + + + + + + + + + + + + + + + + + + + + + + + + + +%A diff --git a/tests/end-to-end/cli/listing-tests-and-groups/list-tests.phpt b/tests/end-to-end/cli/listing-tests-and-groups/list-tests.phpt new file mode 100644 index 00000000000..486a7f49e7d --- /dev/null +++ b/tests/end-to-end/cli/listing-tests-and-groups/list-tests.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --list-tests ../../_files/listing-tests-and-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available tests: + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleExtendingAbstractTest::testOne + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testOne + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testTwo + - PHPUnit\TestFixture\ListingTestsAndGroups\ExampleTest::testThree + - %sexample.phpt diff --git a/tests/end-to-end/cli/log-events-text-invalid-argument.phpt b/tests/end-to-end/cli/log-events-text-invalid-argument.phpt new file mode 100644 index 00000000000..f3c3c5bd28b --- /dev/null +++ b/tests/end-to-end/cli/log-events-text-invalid-argument.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test fails with invalid path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The path "%s" specified for the --log-events-text option could not be resolved diff --git a/tests/end-to-end/cli/log-events-text.phpt b/tests/end-to-end/cli/log-events-text.phpt new file mode 100644 index 00000000000..d76ef45f3bc --- /dev/null +++ b/tests/end-to-end/cli/log-events-text.phpt @@ -0,0 +1,65 @@ +--TEST-- +phpunit --no-output --log-events-text logfile.txt +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($traceFile); + +unlink($traceFile); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (7 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (7 tests) +Test Suite Started (CLI Arguments, 7 tests) +Test Suite Started (PHPUnit\TestFixture\LogEventsText\Test, 7 tests) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +Test Failed (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +Failed asserting that two variables reference the same object. +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +Test Failed (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +Failed asserting that two variables reference the same resource. +Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +Test Suite Finished (PHPUnit\TestFixture\LogEventsText\Test, 7 tests) +Test Suite Finished (CLI Arguments, 7 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/log-events-verbose-text-invalid-argument.phpt b/tests/end-to-end/cli/log-events-verbose-text-invalid-argument.phpt new file mode 100644 index 00000000000..1e22d7c6a09 --- /dev/null +++ b/tests/end-to-end/cli/log-events-verbose-text-invalid-argument.phpt @@ -0,0 +1,19 @@ +--TEST-- +Test fails with invalid path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +The path "%s" specified for the --log-events-verbose-text option could not be resolved diff --git a/tests/end-to-end/cli/log-events-verbose-text.phpt b/tests/end-to-end/cli/log-events-verbose-text.phpt new file mode 100644 index 00000000000..f9653cbd6fd --- /dev/null +++ b/tests/end-to-end/cli/log-events-verbose-text.phpt @@ -0,0 +1,65 @@ +--TEST-- +phpunit --no-output --log-events-verbose-text logfile.txt +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($traceFile); + +unlink($traceFile); +--EXPECTF-- +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Started (%s) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Configured +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Event Facade Sealed +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Loaded (7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Started +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Sorted +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Started (7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Started (CLI Arguments, 7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Started (PHPUnit\TestFixture\LogEventsText\Test, 7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportNull) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportBool) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportInt) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportStr) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportArray) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Failed (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) + %sFailed asserting that two variables reference the same object. +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportObject) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Failed (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) + %sFailed asserting that two variables reference the same resource. +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\LogEventsText\Test::testExportResource) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Finished (PHPUnit\TestFixture\LogEventsText\Test, 7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Finished (CLI Arguments, 7 tests) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/no-log-no-cc.phpt b/tests/end-to-end/cli/no-log-no-cc.phpt new file mode 100644 index 00000000000..a8cefc8cce7 --- /dev/null +++ b/tests/end-to-end/cli/no-log-no-cc.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit -c _files/phpunit.xml --no-logging --log-junit php://stdout _files/NoLogNoCcTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($logfile); + +unlink($logfile); +--EXPECTF-- + + + + + + diff --git a/tests/end-to-end/cli/no-output.phpt b/tests/end-to-end/cli/no-output.phpt new file mode 100644 index 00000000000..300c564b3ed --- /dev/null +++ b/tests/end-to-end/cli/no-output.phpt @@ -0,0 +1,13 @@ +--TEST-- +phpunit --no-output ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECT-- diff --git a/tests/end-to-end/cli/options-after-arguments.phpt b/tests/end-to-end/cli/options-after-arguments.phpt new file mode 100644 index 00000000000..d3024e045e2 --- /dev/null +++ b/tests/end-to-end/cli/options-after-arguments.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit ../../_files/BankAccountTest.php --colors +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +%s[30;42mOK (3 tests, 3 assertions)%s[0m diff --git a/tests/end-to-end/cli/overlapping-testsuite-configuration.phpt b/tests/end-to-end/cli/overlapping-testsuite-configuration.phpt new file mode 100644 index 00000000000..91bc72a1aba --- /dev/null +++ b/tests/end-to-end/cli/overlapping-testsuite-configuration.phpt @@ -0,0 +1,27 @@ +--TEST-- +A test file must not be in more than one test suite configured in the XML configuration file +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %soverlapping-testsuite-configuration%sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot add file %sExampleTest.php to test suite "two" as it was already added to test suite "one" + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/cli/shutdown-handler-with-message.phpt b/tests/end-to-end/cli/shutdown-handler-with-message.phpt new file mode 100644 index 00000000000..03f69137985 --- /dev/null +++ b/tests/end-to-end/cli/shutdown-handler-with-message.phpt @@ -0,0 +1,29 @@ +--TEST-- +Shutdown Handler: exit(1) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +messageFatal error: Premature end of PHP process when running PHPUnit\TestFixture\WithExitTest::testWithMessage. +---- diff --git a/tests/end-to-end/cli/shutdown-handler-without-message.phpt b/tests/end-to-end/cli/shutdown-handler-without-message.phpt new file mode 100644 index 00000000000..019a4bb9ece --- /dev/null +++ b/tests/end-to-end/cli/shutdown-handler-without-message.phpt @@ -0,0 +1,29 @@ +--TEST-- +Shutdown Handler: exit('message') +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Fatal error: Premature end of PHP process when running PHPUnit\TestFixture\WithExitTest::testWithoutMessage. +---- diff --git a/tests/end-to-end/cli/stop-on/stop-on-defect-for-error.phpt b/tests/end-to-end/cli/stop-on/stop-on-defect-for-error.phpt new file mode 100644 index 00000000000..1d0b8e9091e --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-defect-for-error.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first error works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Errored (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/cli/stop-on/stop-on-defect-for-failure.phpt b/tests/end-to-end/cli/stop-on/stop-on-defect-for-failure.phpt new file mode 100644 index 00000000000..b2f6a9be461 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-defect-for-failure.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first failure works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\FailureTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Failed (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\FailureTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/stop-on/stop-on-defect-for-risky.phpt b/tests/end-to-end/cli/stop-on/stop-on-defect-for-risky.phpt new file mode 100644 index 00000000000..5b38eb7275b --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-defect-for-risky.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first risky test works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-defect-for-warning.phpt b/tests/end-to-end/cli/stop-on/stop-on-defect-for-warning.phpt new file mode 100644 index 00000000000..c3cae13763e --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-defect-for-warning.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first warning works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Triggered Warning (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-deprecation.phpt b/tests/end-to-end/cli/stop-on/stop-on-deprecation.phpt new file mode 100644 index 00000000000..4ac3cfad9f7 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-deprecation.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first deprecation works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-error.phpt b/tests/end-to-end/cli/stop-on/stop-on-error.phpt new file mode 100644 index 00000000000..d7dd7834be2 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-error.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first error works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Errored (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\ErrorTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/cli/stop-on/stop-on-failure.phpt b/tests/end-to-end/cli/stop-on/stop-on-failure.phpt new file mode 100644 index 00000000000..a07f58bd38d --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-failure.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first failure works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\FailureTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Failed (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\FailureTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/cli/stop-on/stop-on-incomplete.phpt b/tests/end-to-end/cli/stop-on/stop-on-incomplete.phpt new file mode 100644 index 00000000000..4b23c90d60a --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-incomplete.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first incomplete test works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Marked Incomplete (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-notice.phpt b/tests/end-to-end/cli/stop-on/stop-on-notice.phpt new file mode 100644 index 00000000000..01d62b731b3 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-notice.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first notice works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Triggered Notice (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\NoticeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-risky.phpt b/tests/end-to-end/cli/stop-on/stop-on-risky.phpt new file mode 100644 index 00000000000..7c81b8df921 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-risky.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first risky test works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\RiskyTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-skipped.phpt b/tests/end-to-end/cli/stop-on/stop-on-skipped.phpt new file mode 100644 index 00000000000..37d60f01063 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-skipped.phpt @@ -0,0 +1,32 @@ +--TEST-- +Stopping test execution after first skipped test works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Skipped (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +message +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\SkippedTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-specific-deprecation.phpt b/tests/end-to-end/cli/stop-on/stop-on-specific-deprecation.phpt new file mode 100644 index 00000000000..79843c28b8d --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-specific-deprecation.phpt @@ -0,0 +1,39 @@ +--TEST-- +Stopping test execution after first deprecation where its message contains a given string +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testOne, unknown if issue was triggered in first-party code or third-party code) in %s:%d +...foo... +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testTwo) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testTwo) +Test Triggered Deprecation (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testTwo, unknown if issue was triggered in first-party code or third-party code) in %s:%d +...bar... +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testTwo) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest::testTwo) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\SpecificDeprecationTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/stop-on/stop-on-warning.phpt b/tests/end-to-end/cli/stop-on/stop-on-warning.phpt new file mode 100644 index 00000000000..0f0e72bcb74 --- /dev/null +++ b/tests/end-to-end/cli/stop-on/stop-on-warning.phpt @@ -0,0 +1,33 @@ +--TEST-- +Stopping test execution after first warning works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Prepared (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Triggered Warning (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) in %s:%d +message +Test Passed (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne) +Test Runner Execution Aborted +Test Suite Finished (PHPUnit\TestFixture\TestRunnerStopping\WarningTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/test-directory-does-not-exist.phpt b/tests/end-to-end/cli/test-directory-does-not-exist.phpt new file mode 100644 index 00000000000..f561519bd02 --- /dev/null +++ b/tests/end-to-end/cli/test-directory-does-not-exist.phpt @@ -0,0 +1,15 @@ +--TEST-- +An error is emitted when a configured test directory does not exist +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Test directory "%stest-directory-does-not-exist%stests" not found diff --git a/tests/end-to-end/cli/test-file-not-found.phpt b/tests/end-to-end/cli/test-file-not-found.phpt new file mode 100644 index 00000000000..b0eecacb1f0 --- /dev/null +++ b/tests/end-to-end/cli/test-file-not-found.phpt @@ -0,0 +1,12 @@ +--TEST-- +Test incorrect testFile is reported +--ARGS-- +--no-configuration nonExistingFile.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Test file "nonExistingFile.php" not found diff --git a/tests/end-to-end/cli/test-suite-bootstrap-default.phpt b/tests/end-to-end/cli/test-suite-bootstrap-default.phpt new file mode 100644 index 00000000000..9b5b84a3c1d --- /dev/null +++ b/tests/end-to-end/cli/test-suite-bootstrap-default.phpt @@ -0,0 +1,44 @@ +--TEST-- +All bootstrap scripts are loaded by default +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Bootstrap Finished (%sbootstrap.php) +Bootstrap Finished (%sbootstrap_one.php) +Bootstrap Finished (%sbootstrap_two.php) +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (one, 1 test) +Test Suite Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Prepared (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Passed (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Suite Finished (one, 1 test) +Test Suite Started (two, 1 test) +Test Suite Started (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest::testTwo) +Test Prepared (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest::testTwo) +Test Passed (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest::testTwo) +Test Finished (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\BootstrapForTestSuite\TwoTest, 1 test) +Test Suite Finished (two, 1 test) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/test-suite-bootstrap-exclude.phpt b/tests/end-to-end/cli/test-suite-bootstrap-exclude.phpt new file mode 100644 index 00000000000..8194ddae87f --- /dev/null +++ b/tests/end-to-end/cli/test-suite-bootstrap-exclude.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bootstrap script specific to test suite is not loaded when the test suite is excluded using --exclude-testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Bootstrap Finished (%stests/bootstrap/bootstrap.php) +Bootstrap Finished (%stests/bootstrap/bootstrap_one.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (one, 1 test) +Test Suite Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Prepared (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Passed (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Suite Finished (one, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/test-suite-bootstrap-include.phpt b/tests/end-to-end/cli/test-suite-bootstrap-include.phpt new file mode 100644 index 00000000000..2296fa6ca2d --- /dev/null +++ b/tests/end-to-end/cli/test-suite-bootstrap-include.phpt @@ -0,0 +1,37 @@ +--TEST-- +Bootstrap script specific to test suite is not loaded when the test suite is not selected using --testsuite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s) +Test Runner Configured +Bootstrap Finished (%stests/bootstrap/bootstrap.php) +Bootstrap Finished (%stests/bootstrap/bootstrap_one.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (one, 1 test) +Test Suite Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Prepared (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Passed (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BootstrapForTestSuite\OneTest, 1 test) +Test Suite Finished (one, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/cli/version.phpt b/tests/end-to-end/cli/version.phpt new file mode 100644 index 00000000000..ef47fbaa274 --- /dev/null +++ b/tests/end-to-end/cli/version.phpt @@ -0,0 +1,14 @@ +--TEST-- +phpunit --version +--FILE-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. diff --git a/tests/end-to-end/data-provider/data-provider-provides-more-values-than-test-method-consumes-but-argument-count-validation-is-disabled-using-attribute.phpt b/tests/end-to-end/data-provider/data-provider-provides-more-values-than-test-method-consumes-but-argument-count-validation-is-disabled-using-attribute.phpt new file mode 100644 index 00000000000..3e129a00426 --- /dev/null +++ b/tests/end-to-end/data-provider/data-provider-provides-more-values-than-test-method-consumes-but-argument-count-validation-is-disabled-using-attribute.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../_files/DataProviderTooManyArgumentsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +...... 6 / 6 (100%) + +Time: %s, Memory: %s + +OK (6 tests, 6 assertions) diff --git a/tests/end-to-end/data-provider/dependency-result.phpt b/tests/end-to-end/data-provider/dependency-result.phpt new file mode 100644 index 00000000000..3cde9ce6401 --- /dev/null +++ b/tests/end-to-end/data-provider/dependency-result.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../../_files/DataProviderDependencyResultTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +...E 4 / 4 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\DataProviderDependencyResultTest::testAdd#2 with data (2, 0) +Error: Cannot use positional argument after named argument during unpacking + +ERRORS! +Tests: 4, Assertions: 5, Errors: 1. diff --git a/tests/end-to-end/data-provider/dependency-void.phpt b/tests/end-to-end/data-provider/dependency-void.phpt new file mode 100644 index 00000000000..946f6b3215f --- /dev/null +++ b/tests/end-to-end/data-provider/dependency-void.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../_files/DataProviderDependencyVoidTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +OK (5 tests, 5 assertions) diff --git a/tests/end-to-end/data-provider/log-junit-isolation.phpt b/tests/end-to-end/data-provider/log-junit-isolation.phpt new file mode 100644 index 00000000000..3156f6d6cf8 --- /dev/null +++ b/tests/end-to-end/data-provider/log-junit-isolation.phpt @@ -0,0 +1,38 @@ +--TEST-- +phpunit --process-isolation --log-junit php://stdout ../../_files/DataProviderTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($logfile); + +unlink($logfile); +--EXPECTF-- + + + + + + + + PHPUnit\TestFixture\DataProviderTest::testAdd with data set #2%A +Failed asserting that 2 matches expected 3. +%A +%s:%i + + + + + diff --git a/tests/end-to-end/data-provider/log-junit.phpt b/tests/end-to-end/data-provider/log-junit.phpt new file mode 100644 index 00000000000..f38cfb07ad7 --- /dev/null +++ b/tests/end-to-end/data-provider/log-junit.phpt @@ -0,0 +1,66 @@ +--TEST-- +phpunit --log-junit php://stdout ../../_files/DataProviderTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($logfile); + +unlink($logfile); +--EXPECTF-- + + + + + + + + + PHPUnit\TestFixture\DataProviderTest::testAdd with data set #2%A +Failed asserting that 2 matches expected 3. +%A +%sDataProviderTest.php:%d + + + + + + + + + + PHPUnit\TestFixture\DataProviderWithStringKeysTest::testAdd with data set "1 + 1 = 3"%A +Failed asserting that 2 matches expected 3. +%A +%sDataProviderWithStringKeysTest.php:%d + + + + + + + failure.phptFailed asserting that two strings are equal.%A +--- Expected ++++ Actual +@@ @@ +-'success' ++'failure' +%A +%s:%d + + + diff --git a/tests/end-to-end/data-provider/process-isolation.phpt b/tests/end-to-end/data-provider/process-isolation.phpt new file mode 100644 index 00000000000..2484e53bc7f --- /dev/null +++ b/tests/end-to-end/data-provider/process-isolation.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../_files/TestProcessIsolationWithDataProvider.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/data-provider/requires-phpunit.phpt b/tests/end-to-end/data-provider/requires-phpunit.phpt new file mode 100644 index 00000000000..29aa5d7295a --- /dev/null +++ b/tests/end-to-end/data-provider/requires-phpunit.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit ../../_files/DataProviderRequiresPhpUnitTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +S..SS 5 / 5 (100%) + +Time: %s, Memory: %s + +There were 3 skipped tests: + +1) PHPUnit\TestFixture\DataProviderRequiresPhpUnitTest::testWithInvalidDataProvider +PHPUnit < 10 is required. + +2) PHPUnit\TestFixture\DataProviderRequiresPhpUnitTest::testWithDataProviderThatThrows +PHPUnit < 10 is required. + +3) PHPUnit\TestFixture\DataProviderRequiresPhpUnitTest::testWithDataProviderExternalThatThrows +PHPUnit < 10 is required. + +OK, but some tests were skipped! +Tests: 5, Assertions: 2, Skipped: 3. + diff --git a/tests/end-to-end/data-provider/too-many-arguments.phpt b/tests/end-to-end/data-provider/too-many-arguments.phpt new file mode 100644 index 00000000000..e51a33cb809 --- /dev/null +++ b/tests/end-to-end/data-provider/too-many-arguments.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit ../../_files/DataProviderTooManyArgumentsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +W...... 7 / 7 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\DataProviderTooManyArgumentsTest::testMethodHavingTwoParameters +Data set #2 provided by PHPUnit\TestFixture\DataProviderTooManyArgumentsTest::provider has more arguments (3) than the test method accepts (2) + +%s:%d + +OK, but there were issues! +Tests: 7, Assertions: 7, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/data-provider/warning-when-data-provider-method-has-test-attribute.phpt b/tests/end-to-end/data-provider/warning-when-data-provider-method-has-test-attribute.phpt new file mode 100644 index 00000000000..362d43520a3 --- /dev/null +++ b/tests/end-to-end/data-provider/warning-when-data-provider-method-has-test-attribute.phpt @@ -0,0 +1,41 @@ +--TEST-- +phpunit ../../_files/DataProviderMethodHasTestAttributeTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider for test method PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne) +Test Runner Triggered Warning (Method PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider() used by test method PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne() is also a test method) +Data Provider Method Finished for PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne: +- PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider) +Test Prepared (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider) +Test Passed (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider) +Test Considered Risky (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::provider) +Test Suite Started (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne#0) +Test Prepared (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne#0) +Test Passed (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne#0) +Test Finished (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne#0) +Test Suite Finished (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest::testOne, 1 test) +Test Suite Finished (PHPUnit\TestFixture\DataProviderMethodHasTestAttributeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/data-provider/warning-when-data-provider-method-name-begins-with-test.phpt b/tests/end-to-end/data-provider/warning-when-data-provider-method-name-begins-with-test.phpt new file mode 100644 index 00000000000..ed1d7878ced --- /dev/null +++ b/tests/end-to-end/data-provider/warning-when-data-provider-method-name-begins-with-test.phpt @@ -0,0 +1,41 @@ +--TEST-- +phpunit ../../_files/DataProviderMethodNameStartsWithTestTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider for test method PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne) +Test Runner Triggered Warning (Method PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider() used by test method PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne() is also a test method) +Data Provider Method Finished for PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne: +- PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider) +Test Prepared (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider) +Test Passed (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider) +Test Considered Risky (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testProvider) +Test Suite Started (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne, 1 test) +Test Preparation Started (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne#0) +Test Prepared (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne#0) +Test Passed (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne#0) +Test Finished (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne#0) +Test Suite Finished (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest::testOne, 1 test) +Test Suite Finished (PHPUnit\TestFixture\DataProviderMethodNameStartsWithTestTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/baseline.xml b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/baseline.xml new file mode 100644 index 00000000000..201e019f8e4 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/baseline.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/phpunit.xml b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/phpunit.xml new file mode 100644 index 00000000000..35a68ae4f63 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/phpunit.xml @@ -0,0 +1,21 @@ + + + + + tests + + + + + + src + + + + PHPUnit\TestFixture\BaselineIgnoreDeprecation\trigger_deprecation + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/src/FirstPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/src/FirstPartyClass.php new file mode 100644 index 00000000000..69ae8106f55 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/src/FirstPartyClass.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\BaselineIgnoreDeprecation; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + return true; + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/tests/FirstPartyClassTest.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..0a335791dfd --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/tests/FirstPartyClassTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\BaselineIgnoreDeprecation; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/ThirdPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..e66043ba5ac --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/ThirdPartyClass.php @@ -0,0 +1,12 @@ + require __DIR__ . '/../src/' . $file, + 'ThirdPartyClass.php' => require __DIR__ . '/' . $file, + default => throw new LogicException + }; +}); + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/trigger_deprecation.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/trigger_deprecation.php new file mode 100644 index 00000000000..49d53123aa4 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-baseline-ignore/vendor/trigger_deprecation.php @@ -0,0 +1,7 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/src/FirstPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/src/FirstPartyClass.php new file mode 100644 index 00000000000..e94fad12de3 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/src/FirstPartyClass.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +final class FirstPartyClass +{ + public function method(): true + { + return ThirdPartyClass::A; + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/tests/FirstPartyClassTest.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..b5c44b5867b --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/tests/FirstPartyClassTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/vendor/ThirdPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..a87d69cef99 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-class/vendor/ThirdPartyClass.php @@ -0,0 +1,9 @@ + require __DIR__ . '/../src/' . $file, + 'ThirdPartyClass.php' => require __DIR__ . '/' . $file, + default => throw new LogicException + }; +}); diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/phpunit.xml b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/phpunit.xml new file mode 100644 index 00000000000..ee9592538c3 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/phpunit.xml @@ -0,0 +1,21 @@ + + + + + tests + + + + + + src + + + + PHPUnit\TestFixture\SelfDirectIndirect\trigger_deprecation + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/src/FirstPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/tests/FirstPartyClassTest.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/ThirdPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..b91884d7835 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/ThirdPartyClass.php @@ -0,0 +1,15 @@ +method(); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/autoload.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/autoload.php new file mode 100644 index 00000000000..c5ef0a2856c --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-function/vendor/autoload.php @@ -0,0 +1,4 @@ + + + + + tests + + + + + + src + + + + PHPUnit\TestFixture\SelfDirectIndirect\DeprecationTrigger::triggerDeprecation + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/src/FirstPartyClass.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/tests/FirstPartyClassTest.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/DeprecationTrigger.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/DeprecationTrigger.php new file mode 100644 index 00000000000..b54156ad14b --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/DeprecationTrigger.php @@ -0,0 +1,10 @@ +method(); + } +} diff --git a/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/autoload.php b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/autoload.php new file mode 100644 index 00000000000..fe3e4ed83dd --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/deprecation-trigger-method/vendor/autoload.php @@ -0,0 +1,4 @@ + + + + + tests + + + + + + PHPUnit\TestFixture\DeprecationTrigger\Test::triggerDeprecation + PHPUnit\TestFixture\DeprecationTrigger\triggerDeprecation + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/details-process-isolation/tests/Test.php b/tests/end-to-end/deprecation-trigger/_files/details-process-isolation/tests/Test.php new file mode 100644 index 00000000000..39137a32d4b --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/details-process-isolation/tests/Test.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DeprecationTrigger; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public static function triggerDeprecation(): void + { + trigger_error('deprecation triggered by method', E_USER_DEPRECATED); + } + + public function testDeprecation(): void + { + self::triggerDeprecation(); + triggerDeprecation(); + + $this->assertTrue(true); + } +} + +function triggerDeprecation(): void +{ + trigger_error('deprecation triggered by function', E_USER_DEPRECATED); +} diff --git a/tests/end-to-end/deprecation-trigger/_files/details/phpunit.xml b/tests/end-to-end/deprecation-trigger/_files/details/phpunit.xml new file mode 100644 index 00000000000..d4c4d73e6cd --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/details/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests + + + + + + PHPUnit\TestFixture\DeprecationTrigger\Test::triggerDeprecation + PHPUnit\TestFixture\DeprecationTrigger\triggerDeprecation + + + diff --git a/tests/end-to-end/deprecation-trigger/_files/details/tests/Test.php b/tests/end-to-end/deprecation-trigger/_files/details/tests/Test.php new file mode 100644 index 00000000000..39137a32d4b --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/_files/details/tests/Test.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\DeprecationTrigger; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public static function triggerDeprecation(): void + { + trigger_error('deprecation triggered by method', E_USER_DEPRECATED); + } + + public function testDeprecation(): void + { + self::triggerDeprecation(); + triggerDeprecation(); + + $this->assertTrue(true); + } +} + +function triggerDeprecation(): void +{ + trigger_error('deprecation triggered by function', E_USER_DEPRECATED); +} diff --git a/tests/end-to-end/deprecation-trigger/deprecation-trigger-baseline-ignore.phpt b/tests/end-to-end/deprecation-trigger/deprecation-trigger-baseline-ignore.phpt new file mode 100644 index 00000000000..76ac837a0cd --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/deprecation-trigger-baseline-ignore.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest::testOne, issue triggered by third-party code, suppressed using operator, ignored by baseline) in %s:%d +deprecation in third-party code +Test Passed (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest::testOne) +Test Finished (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\BaselineIgnoreDeprecation\FirstPartyClassTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/deprecation-trigger/deprecation-trigger-class.phpt b/tests/end-to-end/deprecation-trigger/deprecation-trigger-class.phpt new file mode 100644 index 00000000000..fe6b7ff2d47 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/deprecation-trigger-class.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a test that loads a class that triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by third-party code, suppressed using operator) in %s:%d +This class is deprecated +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/deprecation-trigger/deprecation-trigger-function.phpt b/tests/end-to-end/deprecation-trigger/deprecation-trigger-function.phpt new file mode 100644 index 00000000000..1848ed1b102 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/deprecation-trigger-function.phpt @@ -0,0 +1,46 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (default, 2 tests) +Test Suite Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into first-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by third-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Suite Finished (default, 2 tests) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/deprecation-trigger/deprecation-trigger-method.phpt b/tests/end-to-end/deprecation-trigger/deprecation-trigger-method.phpt new file mode 100644 index 00000000000..4bd800f9be4 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/deprecation-trigger-method.phpt @@ -0,0 +1,46 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (default, 2 tests) +Test Suite Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into first-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by third-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Suite Finished (default, 2 tests) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/deprecation-trigger/details-process-isolation.phpt b/tests/end-to-end/deprecation-trigger/details-process-isolation.phpt new file mode 100644 index 00000000000..24f80fdf7c1 --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/details-process-isolation.phpt @@ -0,0 +1,32 @@ +--TEST-- +Configured deprecation triggers are filtered when displaying deprecation details in process isolation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +D 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 2 deprecations: + +1) %sTest.php:25 +deprecation triggered by method + +2) %sTest.php:26 +deprecation triggered by function + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 2. diff --git a/tests/end-to-end/deprecation-trigger/details.phpt b/tests/end-to-end/deprecation-trigger/details.phpt new file mode 100644 index 00000000000..0d7662ff3ac --- /dev/null +++ b/tests/end-to-end/deprecation-trigger/details.phpt @@ -0,0 +1,32 @@ +--TEST-- +Configured deprecation triggers are filtered when displaying deprecation details +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +D 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 2 deprecations: + +1) %sTest.php:25 +deprecation triggered by method + +2) %sTest.php:26 +deprecation triggered by function + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 2. diff --git a/tests/end-to-end/event/_files/AdditionalInformationTest.php b/tests/end-to-end/event/_files/AdditionalInformationTest.php new file mode 100644 index 00000000000..d67efb75fcd --- /dev/null +++ b/tests/end-to-end/event/_files/AdditionalInformationTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class AdditionalInformationTest extends TestCase +{ + public function testSuccess(): void + { + $this->assertTrue(true); + + $this->provideAdditionalInformation('additional information'); + } +} diff --git a/tests/end-to-end/event/_files/ArgumentDataProviderTest.php b/tests/end-to-end/event/_files/ArgumentDataProviderTest.php new file mode 100644 index 00000000000..90be29e089f --- /dev/null +++ b/tests/end-to-end/event/_files/ArgumentDataProviderTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class ArgumentDataProviderTest extends TestCase +{ + public static function values(mixed $argument): array + { + return [[true], [true]]; + } + + #[DataProvider('values')] + public function testSuccess(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/AssertTest.php b/tests/end-to-end/event/_files/AssertTest.php new file mode 100644 index 00000000000..0ca78e7e790 --- /dev/null +++ b/tests/end-to-end/event/_files/AssertTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use function assert; +use PHPUnit\Framework\TestCase; + +final class AssertTest extends TestCase +{ + public function testAssert(): void + { + assert(false); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInPostConditionTest.php b/tests/end-to-end/event/_files/AssertionFailureInPostConditionTest.php new file mode 100644 index 00000000000..f8cfa860c23 --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInPostConditionTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInPostConditionTest extends TestCase +{ + #[PostCondition] + public function postCondition(): void + { + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInPreConditionTest.php b/tests/end-to-end/event/_files/AssertionFailureInPreConditionTest.php new file mode 100644 index 00000000000..69711477dc5 --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInPreConditionTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInPreConditionTest extends TestCase +{ + #[PreCondition] + public function preCondition(): void + { + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInSetUpBeforeClassTest.php b/tests/end-to-end/event/_files/AssertionFailureInSetUpBeforeClassTest.php new file mode 100644 index 00000000000..ce6c0e75bdd --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInSetUpBeforeClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInSetUpBeforeClassTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + self::assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInSetUpTest.php b/tests/end-to-end/event/_files/AssertionFailureInSetUpTest.php new file mode 100644 index 00000000000..cf2829e5f5d --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInSetUpTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInSetUpTest extends TestCase +{ + #[Before] + public function beforeTest(): void + { + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInTearDownAfterClassTest.php b/tests/end-to-end/event/_files/AssertionFailureInTearDownAfterClassTest.php new file mode 100644 index 00000000000..84f81e79f0c --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInTearDownAfterClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInTearDownAfterClassTest extends TestCase +{ + public static function tearDownAfterClass(): void + { + self::assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/AssertionFailureInTearDownTest.php b/tests/end-to-end/event/_files/AssertionFailureInTearDownTest.php new file mode 100644 index 00000000000..110f1d6c6d8 --- /dev/null +++ b/tests/end-to-end/event/_files/AssertionFailureInTearDownTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\TestCase; + +final class AssertionFailureInTearDownTest extends TestCase +{ + #[After] + public function afterTest(): void + { + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest.php b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest.php new file mode 100644 index 00000000000..58112443816 --- /dev/null +++ b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +#[AllowMockObjectsWithoutExpectations] +final class CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest extends TestCase +{ + public function testOne(): void + { + $this->createMock(Example::class); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest.php b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest.php new file mode 100644 index 00000000000..4bc47050bf5 --- /dev/null +++ b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +final class CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest extends TestCase +{ + #[AllowMockObjectsWithoutExpectations] + public function testOne(): void + { + $this->createMock(Example::class); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CreateMockWithoutExpectationsTest.php b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsTest.php new file mode 100644 index 00000000000..4572ee05497 --- /dev/null +++ b/tests/end-to-end/event/_files/CreateMockWithoutExpectationsTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +final class CreateMockWithoutExpectationsTest extends TestCase +{ + public function testOne(): void + { + $this->createMock(Example::class); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php b/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php new file mode 100644 index 00000000000..d529db308ee --- /dev/null +++ b/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +#[AllowMockObjectsWithoutExpectations] +final class CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest extends TestCase +{ + public function testOne(): void + { + $this->createPartialMock(Example::class, []); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsTest.php b/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsTest.php new file mode 100644 index 00000000000..276cf3fe757 --- /dev/null +++ b/tests/end-to-end/event/_files/CreatePartialMockWithoutExpectationsTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +final class CreatePartialMockWithoutExpectationsTest extends TestCase +{ + public function testOne(): void + { + $this->createPartialMock(Example::class, []); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/CustomComparator.php b/tests/end-to-end/event/_files/CustomComparator.php new file mode 100644 index 00000000000..3622ff23af9 --- /dev/null +++ b/tests/end-to-end/event/_files/CustomComparator.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use SebastianBergmann\Comparator\Comparator; + +final class CustomComparator extends Comparator +{ + public function accepts($expected, $actual): bool + { + return true; + } + + public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false): void + { + } +} diff --git a/tests/end-to-end/event/_files/CustomComparatorTest.php b/tests/end-to-end/event/_files/CustomComparatorTest.php new file mode 100644 index 00000000000..e98c7a12b70 --- /dev/null +++ b/tests/end-to-end/event/_files/CustomComparatorTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class CustomComparatorTest extends TestCase +{ + public function testWithCustomComparator(): void + { + $this->registerComparator(new CustomComparator); + + $this->assertEquals(true, false); + } +} diff --git a/tests/end-to-end/event/_files/CustomTestMethodInvocationTest.php b/tests/end-to-end/event/_files/CustomTestMethodInvocationTest.php new file mode 100644 index 00000000000..fe261ff45a1 --- /dev/null +++ b/tests/end-to-end/event/_files/CustomTestMethodInvocationTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class CustomTestMethodInvocationTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + protected function invokeTestMethod(string $methodName, array $testArguments): mixed + { + /** @phpstan-ignore method.dynamicName */ + return $this->{$methodName}(...$testArguments); + } +} diff --git a/tests/end-to-end/event/_files/DataProvider.php b/tests/end-to-end/event/_files/DataProvider.php new file mode 100644 index 00000000000..201e07c04da --- /dev/null +++ b/tests/end-to-end/event/_files/DataProvider.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +final class DataProvider +{ + public static function values(): array + { + return [[true], [true]]; + } +} diff --git a/tests/end-to-end/event/_files/DataProviderDuplicateKeyTest.php b/tests/end-to-end/event/_files/DataProviderDuplicateKeyTest.php new file mode 100644 index 00000000000..15ea0af26be --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderDuplicateKeyTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Generator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderDuplicateKeyTest extends TestCase +{ + public static function provider(): Generator + { + yield 'key' => [true]; + + yield 'key' => [true]; + } + + #[DataProvider('provider')] + public function testSomething(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/DataProviderExternalTest.php b/tests/end-to-end/event/_files/DataProviderExternalTest.php new file mode 100644 index 00000000000..90671b34faf --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderExternalTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\TestCase; + +final class DataProviderExternalTest extends TestCase +{ + #[DataProviderExternal(DataProvider::class, 'values')] + public function testSuccess(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/DataProviderInParentTest.php b/tests/end-to-end/event/_files/DataProviderInParentTest.php new file mode 100644 index 00000000000..d467478dc2d --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderInParentTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderInParentTest extends ParentTestCase +{ +} + +abstract class ParentTestCase extends TestCase +{ + public static function data_provider(): iterable + { + yield [true]; + } + + #[DataProvider('data_provider')] + public function testSomething(bool $var): void + { + $this->assertTrue($var); + } +} diff --git a/tests/end-to-end/event/_files/DataProviderInvalidKeyTest.php b/tests/end-to-end/event/_files/DataProviderInvalidKeyTest.php new file mode 100644 index 00000000000..57fdfd8e16f --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderInvalidKeyTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Iterator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderInvalidKeyTest extends TestCase +{ + public static function provider(): Iterator + { + return new class implements Iterator + { + private int $position; + + public function current(): string + { + return 'value'; + } + + public function next(): void + { + $this->position++; + } + + public function key(): float + { + return 0.1; + } + + public function valid(): bool + { + return $this->position === 0; + } + + public function rewind(): void + { + $this->position = 0; + } + }; + } + + #[DataProvider('provider')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/DataProviderNotIterableTest.php b/tests/end-to-end/event/_files/DataProviderNotIterableTest.php new file mode 100644 index 00000000000..eba22901403 --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderNotIterableTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderNotIterableTest extends TestCase +{ + public static function provider(): string + { + return 'string'; + } + + #[DataProvider('provider')] + public function testSomething(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/DataProviderTest.php b/tests/end-to-end/event/_files/DataProviderTest.php new file mode 100644 index 00000000000..404c6239812 --- /dev/null +++ b/tests/end-to-end/event/_files/DataProviderTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderTest extends TestCase +{ + public static function values(): array + { + return [[true], [true]]; + } + + #[DataProvider('values')] + public function testSuccess(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/DeprecatedFeatureTest.php b/tests/end-to-end/event/_files/DeprecatedFeatureTest.php new file mode 100644 index 00000000000..8cdf64d4f7f --- /dev/null +++ b/tests/end-to-end/event/_files/DeprecatedFeatureTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_DEPRECATED; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class DeprecatedFeatureTest extends TestCase +{ + public function testDeprecatedFeature(): void + { + trigger_error('message', E_USER_DEPRECATED); + @trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testDeprecatedSuppressedErrorGetLast(): void + { + $this->assertNull(error_get_last()); + @trigger_error('message', E_USER_DEPRECATED); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/DeprecatedPhpFeatureTest.php b/tests/end-to-end/event/_files/DeprecatedPhpFeatureTest.php new file mode 100644 index 00000000000..aba4afe4c0c --- /dev/null +++ b/tests/end-to-end/event/_files/DeprecatedPhpFeatureTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use function strlen; +use PHPUnit\Framework\TestCase; + +final class DeprecatedPhpFeatureTest extends TestCase +{ + public function testDeprecatedPhpFeature(): void + { + strlen(null); + @strlen(null); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/DeprecatedPhpunitFeatureTest.php b/tests/end-to-end/event/_files/DeprecatedPhpunitFeatureTest.php new file mode 100644 index 00000000000..835abf7923f --- /dev/null +++ b/tests/end-to-end/event/_files/DeprecatedPhpunitFeatureTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; + +final class DeprecatedPhpunitFeatureTest extends TestCase +{ + public function testDeprecatedPhpunitFeature(): void + { + EventFacade::emitter()->testTriggeredPhpunitDeprecation( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/DynamicDataProviderTest.php b/tests/end-to-end/event/_files/DynamicDataProviderTest.php new file mode 100644 index 00000000000..fa9224e2abe --- /dev/null +++ b/tests/end-to-end/event/_files/DynamicDataProviderTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DynamicDataProviderTest extends TestCase +{ + public function values(): array + { + return [[true], [true]]; + } + + #[DataProvider('values')] + public function testSuccess(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/event/_files/EmptyDataProviderTest.php b/tests/end-to-end/event/_files/EmptyDataProviderTest.php new file mode 100644 index 00000000000..8f4d04f9af5 --- /dev/null +++ b/tests/end-to-end/event/_files/EmptyDataProviderTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class EmptyDataProviderTest extends TestCase +{ + public static function providerMethod(): array + { + return []; + } + + #[DataProvider('providerMethod')] + public function testCase(): void + { + } +} diff --git a/tests/end-to-end/event/_files/EmptyTest.php b/tests/end-to-end/event/_files/EmptyTest.php new file mode 100644 index 00000000000..085a7edd8b0 --- /dev/null +++ b/tests/end-to-end/event/_files/EmptyTest.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class EmptyTest extends TestCase +{ +} diff --git a/tests/end-to-end/event/_files/ErrorTest.php b/tests/end-to-end/event/_files/ErrorTest.php new file mode 100644 index 00000000000..dd82835fec7 --- /dev/null +++ b/tests/end-to-end/event/_files/ErrorTest.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ErrorTest extends TestCase +{ + public function testError(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/event/_files/Example.php b/tests/end-to-end/event/_files/Example.php new file mode 100644 index 00000000000..09994df6c2a --- /dev/null +++ b/tests/end-to-end/event/_files/Example.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +interface Example +{ + public function doSomething(): bool; +} diff --git a/tests/end-to-end/event/_files/ExceptionInDataProviderTest.php b/tests/end-to-end/event/_files/ExceptionInDataProviderTest.php new file mode 100644 index 00000000000..bedfba3136a --- /dev/null +++ b/tests/end-to-end/event/_files/ExceptionInDataProviderTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +final class ExceptionInDataProviderTest extends TestCase +{ + public static function provider(): array + { + throw new RuntimeException('message'); + } + + #[DataProvider('provider')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/ExceptionInSetUpBeforeClassTest.php b/tests/end-to-end/event/_files/ExceptionInSetUpBeforeClassTest.php new file mode 100644 index 00000000000..327010a7280 --- /dev/null +++ b/tests/end-to-end/event/_files/ExceptionInSetUpBeforeClassTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ExceptionInSetUpBeforeClassTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + throw new Exception; + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/ExceptionInSetUpTest.php b/tests/end-to-end/event/_files/ExceptionInSetUpTest.php new file mode 100644 index 00000000000..0e41780445d --- /dev/null +++ b/tests/end-to-end/event/_files/ExceptionInSetUpTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ExceptionInSetUpTest extends TestCase +{ + protected function setUp(): void + { + throw new Exception; + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/ExceptionInTearDownAfterClassTest.php b/tests/end-to-end/event/_files/ExceptionInTearDownAfterClassTest.php new file mode 100644 index 00000000000..22094ddd65d --- /dev/null +++ b/tests/end-to-end/event/_files/ExceptionInTearDownAfterClassTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ExceptionInTearDownAfterClassTest extends TestCase +{ + public static function tearDownAfterClass(): void + { + throw new Exception; + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/ExceptionInTearDownTest.php b/tests/end-to-end/event/_files/ExceptionInTearDownTest.php new file mode 100644 index 00000000000..5b7e35311f9 --- /dev/null +++ b/tests/end-to-end/event/_files/ExceptionInTearDownTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class ExceptionInTearDownTest extends TestCase +{ + protected function tearDown(): void + { + throw new Exception; + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/ExpectedAndUnexpectedAssertionsTest.php b/tests/end-to-end/event/_files/ExpectedAndUnexpectedAssertionsTest.php new file mode 100644 index 00000000000..06118eb390f --- /dev/null +++ b/tests/end-to-end/event/_files/ExpectedAndUnexpectedAssertionsTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +final class ExpectedAndUnexpectedAssertionsTest extends TestCase +{ + #[DoesNotPerformAssertions] + public function testOne(): void + { + } + + public function testTwo(): void + { + $this->expectNotToPerformAssertions(); + } + + #[DoesNotPerformAssertions] + public function testThree(): void + { + $this->assertTrue(true); + } + + public function testFour(): void + { + $this->expectNotToPerformAssertions(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/FailedExpectationTest.php b/tests/end-to-end/event/_files/FailedExpectationTest.php new file mode 100644 index 00000000000..2ee6c88d32c --- /dev/null +++ b/tests/end-to-end/event/_files/FailedExpectationTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; + +final class FailedExpectationTest extends TestCase +{ + public function testOne(): void + { + $mock = $this->createMock(AnInterface::class); + + $mock->expects($this->once())->method('doSomething'); + } +} diff --git a/tests/end-to-end/event/_files/FailureTest.php b/tests/end-to-end/event/_files/FailureTest.php new file mode 100644 index 00000000000..dfa1b9c6c30 --- /dev/null +++ b/tests/end-to-end/event/_files/FailureTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class FailureTest extends TestCase +{ + public function testFailure(): void + { + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/event/_files/FatalTest.php b/tests/end-to-end/event/_files/FatalTest.php new file mode 100644 index 00000000000..aa76e48fd31 --- /dev/null +++ b/tests/end-to-end/event/_files/FatalTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class FatalTest extends TestCase +{ + public function testOne(): void + { + doesNotExist(); + } +} diff --git a/tests/end-to-end/event/_files/IgnoreDeprecationsTest.php b/tests/end-to-end/event/_files/IgnoreDeprecationsTest.php new file mode 100644 index 00000000000..a165a42fbd6 --- /dev/null +++ b/tests/end-to-end/event/_files/IgnoreDeprecationsTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_DEPRECATED; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; + +final class IgnoreDeprecationsTest extends TestCase +{ + #[IgnoreDeprecations] + public function testOne(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + #[IgnoreDeprecations] + public function testOneErrorGetLast(): void + { + $this->assertNull(error_get_last()); + trigger_error('message', E_USER_DEPRECATED); + $this->assertIsArray(error_get_last()); + } + + public function testTwoErrorGetLast(): void + { + $this->assertNull(error_get_last()); + trigger_error('message', E_USER_DEPRECATED); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/IgnoreDeprecationsWithPatternTest.php b/tests/end-to-end/event/_files/IgnoreDeprecationsWithPatternTest.php new file mode 100644 index 00000000000..5c97fc33245 --- /dev/null +++ b/tests/end-to-end/event/_files/IgnoreDeprecationsWithPatternTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; + +#[IgnoreDeprecations('foo')] +final class IgnoreDeprecationsWithPatternTest extends TestCase +{ + #[IgnoreDeprecations('bar')] + public function testOne(): void + { + trigger_error('foo', E_USER_DEPRECATED); + trigger_error('bar', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + trigger_error('foo', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testThree(): void + { + trigger_error('foo', E_USER_DEPRECATED); + trigger_error('baz', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + #[IgnoreDeprecations('bar|baz')] + public function testFour(): void + { + trigger_error('foo', E_USER_DEPRECATED); + trigger_error('bar', E_USER_DEPRECATED); + trigger_error('baz', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/IgnoredDeprecatedPhpunitFeatureTest.php b/tests/end-to-end/event/_files/IgnoredDeprecatedPhpunitFeatureTest.php new file mode 100644 index 00000000000..24c49e6577e --- /dev/null +++ b/tests/end-to-end/event/_files/IgnoredDeprecatedPhpunitFeatureTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\TestCase; + +final class IgnoredDeprecatedPhpunitFeatureTest extends TestCase +{ + #[IgnorePhpunitDeprecations] + public function testDeprecatedPhpunitFeature(): void + { + EventFacade::emitter()->testTriggeredPhpunitDeprecation( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/IncompleteTest.php b/tests/end-to-end/event/_files/IncompleteTest.php new file mode 100644 index 00000000000..b29e84a23ce --- /dev/null +++ b/tests/end-to-end/event/_files/IncompleteTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class IncompleteTest extends TestCase +{ + public function testIncomplete(): void + { + $this->markTestIncomplete('message'); + } +} diff --git a/tests/end-to-end/event/_files/InvalidDataProviderTest.php b/tests/end-to-end/event/_files/InvalidDataProviderTest.php new file mode 100644 index 00000000000..60cff8a16b0 --- /dev/null +++ b/tests/end-to-end/event/_files/InvalidDataProviderTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class InvalidDataProviderTest extends TestCase +{ + public static function provider(): array + { + return [0]; + } + + #[DataProvider('provider')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/InvalidDataProviderWithOneTestPassingTest.php b/tests/end-to-end/event/_files/InvalidDataProviderWithOneTestPassingTest.php new file mode 100644 index 00000000000..e5b0e343bb8 --- /dev/null +++ b/tests/end-to-end/event/_files/InvalidDataProviderWithOneTestPassingTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class InvalidDataProviderWithOneTestPassingTest extends TestCase +{ + public static function provider(): array + { + return [0]; + } + + #[DataProvider('provider')] + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/InvalidDependencyTest.php b/tests/end-to-end/event/_files/InvalidDependencyTest.php new file mode 100644 index 00000000000..ded12c8c6a6 --- /dev/null +++ b/tests/end-to-end/event/_files/InvalidDependencyTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\TestCase; + +final class InvalidDependencyTest extends TestCase +{ + #[Depends('doesNotExist')] + public function testOne(): void + { + $this->assertTrue(true); + } + + #[DependsOnClass('DoesNotExist')] + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/InvalidParameterNameDataProviderTest.php b/tests/end-to-end/event/_files/InvalidParameterNameDataProviderTest.php new file mode 100644 index 00000000000..5e9d3717d43 --- /dev/null +++ b/tests/end-to-end/event/_files/InvalidParameterNameDataProviderTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class InvalidParameterNameDataProviderTest extends TestCase +{ + public static function values(): array + { + return [ + ['value1' => true, 'value2' => true], + ['value3' => true, 'value4' => true], + ]; + } + + #[DataProvider('values')] + public function testSuccess(bool $value1, bool $value2): void + { + $this->assertTrue($value1); + $this->assertTrue($value2); + } +} diff --git a/tests/end-to-end/event/_files/InvalidVersionConstraintTest.php b/tests/end-to-end/event/_files/InvalidVersionConstraintTest.php new file mode 100644 index 00000000000..6d9c262d364 --- /dev/null +++ b/tests/end-to-end/event/_files/InvalidVersionConstraintTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\TestCase; + +final class InvalidVersionConstraintTest extends TestCase +{ + #[RequiresPhp('100')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/MissingDependencyTest.php b/tests/end-to-end/event/_files/MissingDependencyTest.php new file mode 100644 index 00000000000..6d3a39bf0df --- /dev/null +++ b/tests/end-to-end/event/_files/MissingDependencyTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +final class MissingDependencyTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(false); + } + + #[Depends('testOne')] + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php b/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php new file mode 100644 index 00000000000..f11fa2a3c51 --- /dev/null +++ b/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +#[AllowMockObjectsWithoutExpectations] +final class MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest extends TestCase +{ + public function testOne(): void + { + $this->getMockBuilder(Example::class)->getMock(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsTest.php b/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsTest.php new file mode 100644 index 00000000000..f9a351fc0ff --- /dev/null +++ b/tests/end-to-end/event/_files/MockBuilderWithoutExpectationsTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\PHPUnit\Event; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Event\Example; + +final class MockBuilderWithoutExpectationsTest extends TestCase +{ + public function testOne(): void + { + $this->getMockBuilder(Example::class)->getMock(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/MockTest.php b/tests/end-to-end/event/_files/MockTest.php new file mode 100644 index 00000000000..980914092f0 --- /dev/null +++ b/tests/end-to-end/event/_files/MockTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class MockTest extends TestCase +{ + public function testSuccess(): void + { + $mock = $this->createMock(Example::class); + + $mock + ->expects($this->never()) + ->method('doSomething'); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PhpNoticeTest.php b/tests/end-to-end/event/_files/PhpNoticeTest.php new file mode 100644 index 00000000000..b3eadc55f92 --- /dev/null +++ b/tests/end-to-end/event/_files/PhpNoticeTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class PhpNoticeTest extends TestCase +{ + public function testPhpNotice(): void + { + $f = static function (): void + { + }; + + $a = &$f(); + @$a = &$f(); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PhpWarningTest.php b/tests/end-to-end/event/_files/PhpWarningTest.php new file mode 100644 index 00000000000..91d81f06e7a --- /dev/null +++ b/tests/end-to-end/event/_files/PhpWarningTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class PhpWarningTest extends TestCase +{ + public function testPhpWarning(): void + { + $a = $b; + @$a = $b; + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PhpunitNoticeTest.php b/tests/end-to-end/event/_files/PhpunitNoticeTest.php new file mode 100644 index 00000000000..20ab335486b --- /dev/null +++ b/tests/end-to-end/event/_files/PhpunitNoticeTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Event\Facade; +use PHPUnit\Framework\TestCase; + +final class PhpunitNoticeTest extends TestCase +{ + public function testOne(): void + { + Facade::emitter()->testTriggeredPhpunitNotice( + $this->valueObjectForEvents(), + 'message', + ); + + Facade::emitter()->testRunnerTriggeredPhpunitNotice('message'); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PhpunitWarningIgnoredTest.php b/tests/end-to-end/event/_files/PhpunitWarningIgnoredTest.php new file mode 100644 index 00000000000..b5514024571 --- /dev/null +++ b/tests/end-to-end/event/_files/PhpunitWarningIgnoredTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\IgnorePhpunitWarnings; +use PHPUnit\Framework\TestCase; + +final class PhpunitWarningIgnoredTest extends TestCase +{ + public static function dataProvider(): iterable + { + yield [true]; + } + + #[IgnorePhpunitWarnings] + public function testPhpunitWarning(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'warning message', + ); + + $this->assertTrue(true); + } + + #[IgnorePhpunitWarnings('warning message')] + public function testPhpunitWarningWithExactMessage(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'warning message', + ); + + $this->assertTrue(true); + } + + #[IgnorePhpunitWarnings('warn(.*)mess(.*)')] + public function testPhpunitWarningWithRegex(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'warning message', + ); + + $this->assertTrue(true); + } + + #[IgnorePhpunitWarnings('warning/error(.*)')] + public function testPhpunitWarningWithSlashInRegex(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'warning/error message', + ); + + $this->assertTrue(true); + } + + #[IgnorePhpunitWarnings('warn(.*)mess(.*)')] + public function testPhpunitWarningWithWrongPattern(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'another message', + ); + + $this->assertTrue(true); + } + + #[DataProvider('dataProvider')] + #[IgnorePhpunitWarnings] + public function testTooManyArgumentsInDataProvider(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PhpunitWarningTest.php b/tests/end-to-end/event/_files/PhpunitWarningTest.php new file mode 100644 index 00000000000..062cdf08cbb --- /dev/null +++ b/tests/end-to-end/event/_files/PhpunitWarningTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\TestCase; + +final class PhpunitWarningTest extends TestCase +{ + public function testPhpunitWarning(): void + { + EventFacade::emitter()->testTriggeredPhpunitWarning( + $this->valueObjectForEvents(), + 'message', + ); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/PrivateDataProviderTest.php b/tests/end-to-end/event/_files/PrivateDataProviderTest.php new file mode 100644 index 00000000000..e5fe4e178d5 --- /dev/null +++ b/tests/end-to-end/event/_files/PrivateDataProviderTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class PrivateDataProviderTest extends TestCase +{ + #[DataProvider('values')] + public function testSuccess(bool $value): void + { + $this->assertTrue($value); + } + + private static function values(): array + { + return [[true], [true]]; + } +} diff --git a/tests/end-to-end/event/_files/RiskyBecauseGlobalStateModificationTest.php b/tests/end-to-end/event/_files/RiskyBecauseGlobalStateModificationTest.php new file mode 100644 index 00000000000..589e74333a6 --- /dev/null +++ b/tests/end-to-end/event/_files/RiskyBecauseGlobalStateModificationTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class RiskyBecauseGlobalStateModificationTest extends TestCase +{ + public function testOne(): void + { + $GLOBALS['variable'] = 'value'; + } +} diff --git a/tests/end-to-end/event/_files/RiskyBecauseNoAssertionsTest.php b/tests/end-to-end/event/_files/RiskyBecauseNoAssertionsTest.php new file mode 100644 index 00000000000..93964490b29 --- /dev/null +++ b/tests/end-to-end/event/_files/RiskyBecauseNoAssertionsTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class RiskyBecauseNoAssertionsTest extends TestCase +{ + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/event/_files/RiskyBecauseOutputTest.php b/tests/end-to-end/event/_files/RiskyBecauseOutputTest.php new file mode 100644 index 00000000000..6bd415b4809 --- /dev/null +++ b/tests/end-to-end/event/_files/RiskyBecauseOutputTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class RiskyBecauseOutputTest extends TestCase +{ + public function testOne(): void + { + print '*'; + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/RiskyBecauseTimeLimitExceededTest.php b/tests/end-to-end/event/_files/RiskyBecauseTimeLimitExceededTest.php new file mode 100644 index 00000000000..05f6a2adae5 --- /dev/null +++ b/tests/end-to-end/event/_files/RiskyBecauseTimeLimitExceededTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use function sleep; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +final class RiskyBecauseTimeLimitExceededTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + + sleep(2); + } +} diff --git a/tests/end-to-end/event/_files/RiskyWithMultipleReasonsTest.php b/tests/end-to-end/event/_files/RiskyWithMultipleReasonsTest.php new file mode 100644 index 00000000000..f722a94d198 --- /dev/null +++ b/tests/end-to-end/event/_files/RiskyWithMultipleReasonsTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class RiskyWithMultipleReasonsTest extends TestCase +{ + public function testOne(): void + { + $GLOBALS['variable'] = 'value'; + } +} diff --git a/tests/end-to-end/event/_files/SeparateProcessesTest.php b/tests/end-to-end/event/_files/SeparateProcessesTest.php new file mode 100644 index 00000000000..549af0818b0 --- /dev/null +++ b/tests/end-to-end/event/_files/SeparateProcessesTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class SeparateProcessesTest extends TestCase +{ + public function testOne(): array + { + exit; + } +} diff --git a/tests/end-to-end/event/_files/SkippedInSetupBeforeClassTest.php b/tests/end-to-end/event/_files/SkippedInSetupBeforeClassTest.php new file mode 100644 index 00000000000..0e53c97fe72 --- /dev/null +++ b/tests/end-to-end/event/_files/SkippedInSetupBeforeClassTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class SkippedInSetupBeforeClassTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + self::markTestSkipped('message'); + } + + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/event/_files/SkippedInSetupTest.php b/tests/end-to-end/event/_files/SkippedInSetupTest.php new file mode 100644 index 00000000000..c9e81f53193 --- /dev/null +++ b/tests/end-to-end/event/_files/SkippedInSetupTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class SkippedInSetupTest extends TestCase +{ + protected function setUp(): void + { + $this->markTestSkipped(); + } + + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/event/_files/SkippedTest.php b/tests/end-to-end/event/_files/SkippedTest.php new file mode 100644 index 00000000000..916188c2112 --- /dev/null +++ b/tests/end-to-end/event/_files/SkippedTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class SkippedTest extends TestCase +{ + public function testSkipped(): void + { + $this->markTestSkipped('message'); + } +} diff --git a/tests/end-to-end/event/_files/StubTest.php b/tests/end-to-end/event/_files/StubTest.php new file mode 100644 index 00000000000..e33bdd4d4a7 --- /dev/null +++ b/tests/end-to-end/event/_files/StubTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class StubTest extends TestCase +{ + public function testSuccess(): void + { + $this->createStub(Example::class); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/SuccessTest.php b/tests/end-to-end/event/_files/SuccessTest.php new file mode 100644 index 00000000000..75211879366 --- /dev/null +++ b/tests/end-to-end/event/_files/SuccessTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class SuccessTest extends TestCase +{ + public function testSuccess(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/SuccessfulExpectationTest.php b/tests/end-to-end/event/_files/SuccessfulExpectationTest.php new file mode 100644 index 00000000000..0a4d3c9e2ac --- /dev/null +++ b/tests/end-to-end/event/_files/SuccessfulExpectationTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; + +final class SuccessfulExpectationTest extends TestCase +{ + public function testOne(): void + { + $mock = $this->createMock(AnInterface::class); + + $mock->expects($this->once())->method('doSomething'); + + $mock->doSomething(); + } +} diff --git a/tests/end-to-end/event/_files/SuppressedUserNoticeTest.php b/tests/end-to-end/event/_files/SuppressedUserNoticeTest.php new file mode 100644 index 00000000000..d280987cd2b --- /dev/null +++ b/tests/end-to-end/event/_files/SuppressedUserNoticeTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_NOTICE; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class SuppressedUserNoticeTest extends TestCase +{ + public function testSuppressedUserNotice(): void + { + $this->assertTrue(true); + + @trigger_error('message', E_USER_NOTICE); + } + + public function testSuppressedUserNoticeErrorGetLast(): void + { + $this->assertNull(error_get_last()); + @trigger_error('message', E_USER_NOTICE); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/SuppressedUserWarningTest.php b/tests/end-to-end/event/_files/SuppressedUserWarningTest.php new file mode 100644 index 00000000000..d6c362f9cab --- /dev/null +++ b/tests/end-to-end/event/_files/SuppressedUserWarningTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_WARNING; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class SuppressedUserWarningTest extends TestCase +{ + public function testSuppressedUserWarning(): void + { + $this->assertTrue(true); + + @trigger_error('message', E_USER_WARNING); + } + + public function testSuppressedUserWarningErrorGetLast(): void + { + $this->assertNull(error_get_last()); + @trigger_error('message', E_USER_WARNING); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/TemplateMethodsTest.php b/tests/end-to-end/event/_files/TemplateMethodsTest.php new file mode 100644 index 00000000000..b1ee82505b5 --- /dev/null +++ b/tests/end-to-end/event/_files/TemplateMethodsTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class TemplateMethodsTest extends TestCase +{ + public static function setUpBeforeClass(): void + { + } + + public static function tearDownAfterClass(): void + { + } + + protected function setUp(): void + { + } + + protected function assertPreConditions(): void + { + } + + protected function assertPostConditions(): void + { + } + + protected function tearDown(): void + { + } + + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/UnsatisfiedRequirementBeforeClassMethodTest.php b/tests/end-to-end/event/_files/UnsatisfiedRequirementBeforeClassMethodTest.php new file mode 100644 index 00000000000..ad0b2c412e0 --- /dev/null +++ b/tests/end-to-end/event/_files/UnsatisfiedRequirementBeforeClassMethodTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\TestCase; + +final class UnsatisfiedRequirementBeforeClassMethodTest extends TestCase +{ + #[RequiresPhp('^100.0')] + public static function setUpBeforeClass(): void + { + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/UnsatisfiedRequirementClassTest.php b/tests/end-to-end/event/_files/UnsatisfiedRequirementClassTest.php new file mode 100644 index 00000000000..5013d5c16bc --- /dev/null +++ b/tests/end-to-end/event/_files/UnsatisfiedRequirementClassTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\TestCase; + +#[RequiresPhp('^100.0')] +final class UnsatisfiedRequirementClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/UnsatisfiedRequirementMethodTest.php b/tests/end-to-end/event/_files/UnsatisfiedRequirementMethodTest.php new file mode 100644 index 00000000000..636e901f94d --- /dev/null +++ b/tests/end-to-end/event/_files/UnsatisfiedRequirementMethodTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\TestCase; + +final class UnsatisfiedRequirementMethodTest extends TestCase +{ + #[RequiresPhp('^100.0')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/UserErrorTest.php b/tests/end-to-end/event/_files/UserErrorTest.php new file mode 100644 index 00000000000..62ea7d170f8 --- /dev/null +++ b/tests/end-to-end/event/_files/UserErrorTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_ERROR; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class UserErrorTest extends TestCase +{ + public function testUserError(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_ERROR); + } + + public function testUserErrorMustAbortExecution(): void + { + trigger_error('message', E_USER_ERROR); + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/event/_files/UserNoticeTest.php b/tests/end-to-end/event/_files/UserNoticeTest.php new file mode 100644 index 00000000000..17046c78f5c --- /dev/null +++ b/tests/end-to-end/event/_files/UserNoticeTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_NOTICE; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class UserNoticeTest extends TestCase +{ + public function testUserNotice(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_NOTICE); + } + + public function testUserNoticeErrorGetLast(): void + { + $this->assertNull(error_get_last()); + trigger_error('message', E_USER_NOTICE); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/UserWarningTest.php b/tests/end-to-end/event/_files/UserWarningTest.php new file mode 100644 index 00000000000..21b232ee50a --- /dev/null +++ b/tests/end-to-end/event/_files/UserWarningTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_WARNING; +use function error_get_last; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class UserWarningTest extends TestCase +{ + public function testUserWarning(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_WARNING); + } + + public function testUserWarningErrorGetLast(): void + { + $this->assertNull(error_get_last()); + trigger_error('message', E_USER_WARNING); + $this->assertIsArray(error_get_last()); + } +} diff --git a/tests/end-to-end/event/_files/XdebugIsDisabled.php b/tests/end-to-end/event/_files/XdebugIsDisabled.php new file mode 100644 index 00000000000..e2cb32d2e92 --- /dev/null +++ b/tests/end-to-end/event/_files/XdebugIsDisabled.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use function extension_loaded; +use function ini_get; +use PHPUnit\Framework\TestCase; + +final class XdebugIsDisabled extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(extension_loaded('xdebug')); + $this->assertSame('', (string) ini_get('xdebug.mode')); + } +} diff --git a/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/bootstrap.php b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/bootstrap.php new file mode 100644 index 00000000000..fc1f5dc3f29 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/bootstrap.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten; + +use function set_error_handler; + +set_error_handler( + static function (int $errorNumber, string $errorString, string $errorFile, int $errorLine): bool + { + return true; + }, +); diff --git a/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/phpunit.xml b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/phpunit.xml new file mode 100644 index 00000000000..0e0f270cea9 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/phpunit.xml @@ -0,0 +1,11 @@ + + + + + tests + + + diff --git a/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/tests/ExampleTest.php b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/tests/ExampleTest.php new file mode 100644 index 00000000000..fa5b3fc3d34 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit/tests/ExampleTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class ExampleTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureException.php b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureException.php new file mode 100644 index 00000000000..ab913bcc3c7 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use Exception; + +final class CustomFailureException extends Exception implements CustomFailureInterface +{ +} diff --git a/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterface.php b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterface.php new file mode 100644 index 00000000000..b8bb4e120b8 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterface.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +interface CustomFailureInterface +{ +} diff --git a/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterfaceTest.php b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterfaceTest.php new file mode 100644 index 00000000000..2b1d52cf967 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-failure-interface/CustomFailureInterfaceTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use PHPUnit\Framework\TestCase; + +final class CustomFailureInterfaceTest extends TestCase +{ + public function testOne(): void + { + $this->registerFailureType(CustomFailureInterface::class); + + $this->assertTrue(true); + + throw new CustomFailureException('this should be treated as a failure'); + } + + public function testTwo(): void + { + throw new CustomFailureException('this should be treated as an error'); + } +} diff --git a/tests/end-to-end/event/_files/custom-failure-interface/bootstrap.php b/tests/end-to-end/event/_files/custom-failure-interface/bootstrap.php new file mode 100644 index 00000000000..560c65452b7 --- /dev/null +++ b/tests/end-to-end/event/_files/custom-failure-interface/bootstrap.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/CustomFailureInterface.php'; + +require __DIR__ . '/CustomFailureException.php'; diff --git a/tests/end-to-end/event/_files/error-handler-can-be-disabled/phpunit.xml b/tests/end-to-end/event/_files/error-handler-can-be-disabled/phpunit.xml new file mode 100644 index 00000000000..07bc4a06a1a --- /dev/null +++ b/tests/end-to-end/event/_files/error-handler-can-be-disabled/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + diff --git a/tests/end-to-end/event/_files/error-handler-can-be-disabled/src/Foo.php b/tests/end-to-end/event/_files/error-handler-can-be-disabled/src/Foo.php new file mode 100644 index 00000000000..d503df1b221 --- /dev/null +++ b/tests/end-to-end/event/_files/error-handler-can-be-disabled/src/Foo.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled; + +use const E_USER_WARNING; +use function error_get_last; +use function fopen; +use function trigger_error; +use Exception; + +final class Foo +{ + public function methodA($fileName) + { + $stream_handle = @fopen($fileName, 'wb'); + + if ($stream_handle === false) { + $error = error_get_last(); + + throw new Exception($error['message']); + } + + return $stream_handle; + } + + public function methodB(): ?array + { + @trigger_error('Triggering', E_USER_WARNING); + + return error_get_last(); + } +} diff --git a/tests/end-to-end/event/_files/error-handler-can-be-disabled/tests/FooTest.php b/tests/end-to-end/event/_files/error-handler-can-be-disabled/tests/FooTest.php new file mode 100644 index 00000000000..79222867423 --- /dev/null +++ b/tests/end-to-end/event/_files/error-handler-can-be-disabled/tests/FooTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled; + +use function restore_error_handler; +use function set_error_handler; +use function sys_get_temp_dir; +use function tempnam; +use Exception; +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + #[WithoutErrorHandler] + public function testMethodA(): void + { + $fileName = tempnam(sys_get_temp_dir(), 'RLT') . '/missing/directory'; + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Failed to open stream'); + + (new Foo)->methodA($fileName); + } + + #[WithoutErrorHandler] + public function testMethodB(): void + { + $this->assertSame('Triggering', (new Foo)->methodB()['message']); + } + + public function testErrorHandlerSet(): void + { + $this->assertIsCallable($this->getErrorHandler()); + } + + #[WithoutErrorHandler] + public function testErrorHandlerIsNotSet(): void + { + $this->assertNull($this->getErrorHandler()); + } + + /** + * @return null|callable + */ + private function getErrorHandler() + { + $res = set_error_handler(static fn () => false); + restore_error_handler(); + + return $res; + } +} diff --git a/tests/end-to-end/event/_files/invalid-coverage-metadata/phpunit.xml b/tests/end-to-end/event/_files/invalid-coverage-metadata/phpunit.xml new file mode 100644 index 00000000000..c05484a928c --- /dev/null +++ b/tests/end-to-end/event/_files/invalid-coverage-metadata/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/event/_files/invalid-coverage-metadata/src/Foo.php b/tests/end-to-end/event/_files/invalid-coverage-metadata/src/Foo.php new file mode 100644 index 00000000000..44f5b812404 --- /dev/null +++ b/tests/end-to-end/event/_files/invalid-coverage-metadata/src/Foo.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\InvalidCoverageMetadata; + +final class Foo +{ +} diff --git a/tests/end-to-end/event/_files/invalid-coverage-metadata/tests/InvalidCoverageMetadataTest.php b/tests/end-to-end/event/_files/invalid-coverage-metadata/tests/InvalidCoverageMetadataTest.php new file mode 100644 index 00000000000..1e6dec4f4ab --- /dev/null +++ b/tests/end-to-end/event/_files/invalid-coverage-metadata/tests/InvalidCoverageMetadataTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\InvalidCoverageMetadata; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass('PHPUnit\TestFixture\Event\InvalidCoverageMetadata\This\Does\Not\Exist')] +final class InvalidCoverageMetadataTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/test-risky-code-coverage/phpunit.xml b/tests/end-to-end/event/_files/test-risky-code-coverage/phpunit.xml new file mode 100644 index 00000000000..27a18a80d36 --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-code-coverage/phpunit.xml @@ -0,0 +1,21 @@ + + + + + tests + + + + + + src + + + + src/autoload.php + + + diff --git a/tests/end-to-end/event/_files/test-risky-code-coverage/src/Bar.php b/tests/end-to-end/event/_files/test-risky-code-coverage/src/Bar.php new file mode 100644 index 00000000000..6d2230a192b --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-code-coverage/src/Bar.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyCodeCoverage; + +final class Bar +{ + public function doSomethingElse(): bool + { + return true; + } +} diff --git a/tests/end-to-end/event/_files/test-risky-code-coverage/src/Foo.php b/tests/end-to-end/event/_files/test-risky-code-coverage/src/Foo.php new file mode 100644 index 00000000000..09d94dfa19e --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-code-coverage/src/Foo.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyCodeCoverage; + +final class Foo +{ + public function doSomething(): bool + { + return (new Bar)->doSomethingElse(); + } +} diff --git a/tests/end-to-end/event/_files/test-risky-code-coverage/src/autoload.php b/tests/end-to-end/event/_files/test-risky-code-coverage/src/autoload.php new file mode 100644 index 00000000000..64b31ae4551 --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-code-coverage/src/autoload.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyCodeCoverage; + +require __DIR__ . '/Foo.php'; + +require __DIR__ . '/Bar.php'; diff --git a/tests/end-to-end/event/_files/test-risky-code-coverage/tests/FooTest.php b/tests/end-to-end/event/_files/test-risky-code-coverage/tests/FooTest.php new file mode 100644 index 00000000000..23c4edaf66a --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-code-coverage/tests/FooTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyCodeCoverage; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Foo::class)] +final class FooTest extends TestCase +{ + public function testSomething(): void + { + $this->assertTrue((new Foo)->doSomething()); + } +} diff --git a/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/LargeTest.php b/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/LargeTest.php new file mode 100644 index 00000000000..567ed9a398b --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/LargeTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest; + +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\TestCase; + +#[Large] +final class LargeTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/SmallTest.php b/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/SmallTest.php new file mode 100644 index 00000000000..96a072a2e8e --- /dev/null +++ b/tests/end-to-end/event/_files/test-risky-depends-on-larger-test/SmallTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest; + +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +final class SmallTest extends TestCase +{ + #[DependsExternal(LargeTest::class, 'testOne')] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/event/additional-information.phpt b/tests/end-to-end/event/additional-information.phpt new file mode 100644 index 00000000000..70d17f5fe45 --- /dev/null +++ b/tests/end-to-end/event/additional-information.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a successful test that provides additional information +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AdditionalInformationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AdditionalInformationTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\AdditionalInformationTest::testSuccess) +Test Provided Additional Information +additional information +Test Passed (PHPUnit\TestFixture\Event\AdditionalInformationTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\AdditionalInformationTest::testSuccess) +Test Suite Finished (PHPUnit\TestFixture\Event\AdditionalInformationTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/assert-failure.phpt b/tests/end-to-end/event/assert-failure.phpt new file mode 100644 index 00000000000..16c437ca968 --- /dev/null +++ b/tests/end-to-end/event/assert-failure.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of assert() +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertTest::testAssert) +Test Prepared (PHPUnit\TestFixture\Event\AssertTest::testAssert) +Test Failed (PHPUnit\TestFixture\Event\AssertTest::testAssert) +assert(false) +Test Finished (PHPUnit\TestFixture\Event\AssertTest::testAssert) +Test Suite Finished (PHPUnit\TestFixture\Event\AssertTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-after-class-method.phpt b/tests/end-to-end/event/assertion-failure-in-after-class-method.phpt new file mode 100644 index 00000000000..535f4ff9dda --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-after-class-method.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "after last test" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::testOne) +After Last Test Method Called (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::tearDownAfterClass) +After Last Test Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::tearDownAfterClass) +Failed asserting that false is true. +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest::tearDownAfterClass +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInTearDownAfterClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-after-test-method.phpt b/tests/end-to-end/event/assertion-failure-in-after-test-method.phpt new file mode 100644 index 00000000000..a192920dece --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-after-test-method.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "after test" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::testOne) +After Test Method Called (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::afterTest) +After Test Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::afterTest) +Failed asserting that false is true. +After Test Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::afterTest +Test Failed (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInTearDownTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-before-class-method.phpt b/tests/end-to-end/event/assertion-failure-in-before-class-method.phpt new file mode 100644 index 00000000000..7e47bb8cf35 --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-before-class-method.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "before first test" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInSetUpBeforeClassTest, 1 test) +Before First Test Method Called (PHPUnit\TestFixture\Event\AssertionFailureInSetUpBeforeClassTest::setUpBeforeClass) +Before First Test Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInSetUpBeforeClassTest::setUpBeforeClass) +Failed asserting that false is true. +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInSetUpBeforeClassTest::setUpBeforeClass +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInSetUpBeforeClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-before-test-method.phpt b/tests/end-to-end/event/assertion-failure-in-before-test-method.phpt new file mode 100644 index 00000000000..9d20fe9c771 --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-before-test-method.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "before test" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::testOne) +Before Test Method Called (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::beforeTest) +Before Test Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::beforeTest) +Failed asserting that false is true. +Before Test Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::beforeTest +Test Preparation Failed (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::testOne) +Failed asserting that false is true. +Test Failed (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInSetUpTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-postcondition-method.phpt b/tests/end-to-end/event/assertion-failure-in-postcondition-method.phpt new file mode 100644 index 00000000000..faf026b1c90 --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-postcondition-method.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "post condition" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::testOne) +Post Condition Method Called (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::postCondition) +Post Condition Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::postCondition) +Failed asserting that false is true. +Post Condition Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::postCondition +Test Failed (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInPostConditionTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-precondition-method.phpt b/tests/end-to-end/event/assertion-failure-in-precondition-method.phpt new file mode 100644 index 00000000000..d02904f0d26 --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-precondition-method.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in a "pre condition" method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::testOne) +Pre Condition Method Called (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::preCondition) +Pre Condition Method Failed (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::preCondition) +Failed asserting that false is true. +Pre Condition Method Finished: +- PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::preCondition +Test Preparation Failed (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::testOne) +Failed asserting that false is true. +Test Failed (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\AssertionFailureInPreConditionTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/assertion-failure-in-test-method.phpt b/tests/end-to-end/event/assertion-failure-in-test-method.phpt new file mode 100644 index 00000000000..e74e57fde9e --- /dev/null +++ b/tests/end-to-end/event/assertion-failure-in-test-method.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that fails because of an assertion failure in the test method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\FailureTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\FailureTest::testFailure) +Test Prepared (PHPUnit\TestFixture\Event\FailureTest::testFailure) +Test Failed (PHPUnit\TestFixture\Event\FailureTest::testFailure) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\FailureTest::testFailure) +Test Suite Finished (PHPUnit\TestFixture\Event\FailureTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/custom-comparator.phpt b/tests/end-to-end/event/custom-comparator.phpt new file mode 100644 index 00000000000..3665207d1ba --- /dev/null +++ b/tests/end-to-end/event/custom-comparator.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a successful test that uses assertEquals() with a custom comparator +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sCustomComparator.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\CustomComparatorTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\CustomComparatorTest::testWithCustomComparator) +Test Prepared (PHPUnit\TestFixture\Event\CustomComparatorTest::testWithCustomComparator) +Comparator Registered (PHPUnit\TestFixture\Event\CustomComparator) +Test Passed (PHPUnit\TestFixture\Event\CustomComparatorTest::testWithCustomComparator) +Test Finished (PHPUnit\TestFixture\Event\CustomComparatorTest::testWithCustomComparator) +Test Suite Finished (PHPUnit\TestFixture\Event\CustomComparatorTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit.phpt b/tests/end-to-end/event/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit.phpt new file mode 100644 index 00000000000..f48d3e909bf --- /dev/null +++ b/tests/end-to-end/event/custom-error-handler-registered-in-bootstrap-is-not-overwritten-by-phpunit.phpt @@ -0,0 +1,35 @@ +--TEST-- +A custom error handler registered in the test suite's bootstrap script using set_error_handler() is not overwritten by PHPUnit by default +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sbootstrap.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\ErrorHandlerIsNotOverwritten\ExampleTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/custom-test-method-invocation.phpt b/tests/end-to-end/event/custom-test-method-invocation.phpt new file mode 100644 index 00000000000..d7e2481f27d --- /dev/null +++ b/tests/end-to-end/event/custom-test-method-invocation.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses custom test method invocation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest::testOne) +Custom Test Method Invocation Used (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest::invokeTestMethod) +Test Passed (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\CustomTestMethodInvocationTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/data-provider-does-not-return-iterable.phpt b/tests/end-to-end/event/data-provider-does-not-return-iterable.phpt new file mode 100644 index 00000000000..ae8ac38e6c7 --- /dev/null +++ b/tests/end-to-end/event/data-provider-does-not-return-iterable.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that does not return an iterable +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderNotIterableTest::provider for test method PHPUnit\TestFixture\Event\DataProviderNotIterableTest::testSomething) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderNotIterableTest::testSomething: +- PHPUnit\TestFixture\Event\DataProviderNotIterableTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DataProviderNotIterableTest::testSomething) +The data provider PHPUnit\TestFixture\Event\DataProviderNotIterableTest::provider specified for PHPUnit\TestFixture\Event\DataProviderNotIterableTest::testSomething is invalid +Data Provider method PHPUnit\TestFixture\Event\DataProviderNotIterableTest::provider() does not return an iterable +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DataProviderNotIterableTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-duplicate-key.phpt b/tests/end-to-end/event/data-provider-duplicate-key.phpt new file mode 100644 index 00000000000..2fc6b652a59 --- /dev/null +++ b/tests/end-to-end/event/data-provider-duplicate-key.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that provides data with duplicate keys +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider for test method PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething: +- PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething) +The data provider specified for PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::testSomething is invalid +The key "key" has already been defined by provider PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest::provider +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DataProviderDuplicateKeyTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-empty.phpt b/tests/end-to-end/event/data-provider-empty.phpt new file mode 100644 index 00000000000..83c6f4c54af --- /dev/null +++ b/tests/end-to-end/event/data-provider-empty.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that provides no data +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\EmptyDataProviderTest::providerMethod for test method PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase) +Data Provider Method Finished for PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase: +- PHPUnit\TestFixture\Event\EmptyDataProviderTest::providerMethod +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase) +The data provider specified for PHPUnit\TestFixture\Event\EmptyDataProviderTest::testCase is invalid +Empty data set provided by data provider +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\EmptyDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-exception.phpt b/tests/end-to-end/event/data-provider-exception.phpt new file mode 100644 index 00000000000..23c1d97ad46 --- /dev/null +++ b/tests/end-to-end/event/data-provider-exception.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that raises an exception +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider for test method PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne) +Data Provider Method Finished for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne: +- PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne) +The data provider PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::provider specified for PHPUnit\TestFixture\Event\ExceptionInDataProviderTest::testOne is invalid +message +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ExceptionInDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-expects-argument.phpt b/tests/end-to-end/event/data-provider-expects-argument.phpt new file mode 100644 index 00000000000..1fddf9a4251 --- /dev/null +++ b/tests/end-to-end/event/data-provider-expects-argument.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that expects an argument +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values for test method PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess: +- PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess) +The data provider PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values specified for PHPUnit\TestFixture\Event\ArgumentDataProviderTest::testSuccess is invalid +Data Provider method PHPUnit\TestFixture\Event\ArgumentDataProviderTest::values() expects an argument +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\ArgumentDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-external.phpt b/tests/end-to-end/event/data-provider-external.phpt new file mode 100644 index 00000000000..03ff9791292 --- /dev/null +++ b/tests/end-to-end/event/data-provider-external.phpt @@ -0,0 +1,41 @@ +--TEST-- +The right events are emitted in the right order for a successful test that uses a data provider method in a different class +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sDataProvider.php) +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProvider::values for test method PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess: +- PHPUnit\TestFixture\Event\DataProvider::values +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderExternalTest, 2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0) +Test Prepared (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0) +Test Passed (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0) +Test Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#0) +Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1) +Test Prepared (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1) +Test Passed (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1) +Test Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess#1) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest::testSuccess, 2 tests) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderExternalTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/data-provider-in-parent-class.phpt b/tests/end-to-end/event/data-provider-in-parent-class.phpt new file mode 100644 index 00000000000..9a96a36329c --- /dev/null +++ b/tests/end-to-end/event/data-provider-in-parent-class.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that provides no data +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderInParentTest::data_provider for test method PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething: +- PHPUnit\TestFixture\Event\DataProviderInParentTest::data_provider +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderInParentTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0) +Test Prepared (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0) +Test Passed (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0) +Test Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething#0) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest::testSomething, 1 test) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderInParentTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/data-provider-invalid-argument-name.phpt b/tests/end-to-end/event/data-provider-invalid-argument-name.phpt new file mode 100644 index 00000000000..d5b8b946f5b --- /dev/null +++ b/tests/end-to-end/event/data-provider-invalid-argument-name.phpt @@ -0,0 +1,39 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that provides data with invalid argument names +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::values for test method PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess: +- PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::values +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest, 2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0) +Test Prepared (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0) +Test Passed (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0) +Test Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#0) +Test Preparation Started (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1) +Test Prepared (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1) +Test Errored (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1) +Unknown named parameter $value3 +Test Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess#1) +Test Suite Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest::testSuccess, 2 tests) +Test Suite Finished (PHPUnit\TestFixture\Event\InvalidParameterNameDataProviderTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-invalid-key.phpt b/tests/end-to-end/event/data-provider-invalid-key.phpt new file mode 100644 index 00000000000..2ef8fbc2554 --- /dev/null +++ b/tests/end-to-end/event/data-provider-invalid-key.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that provides data with invalid keys +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::provider for test method PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::testOne) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::testOne: +- PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::testOne) +The data provider specified for PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest::testOne is invalid +The key must be an integer or a string, float given +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DataProviderInvalidKeyTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-not-public.phpt b/tests/end-to-end/event/data-provider-not-public.phpt new file mode 100644 index 00000000000..647b4fac6e8 --- /dev/null +++ b/tests/end-to-end/event/data-provider-not-public.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that is not public +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\PrivateDataProviderTest::values for test method PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess: +- PHPUnit\TestFixture\Event\PrivateDataProviderTest::values +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess) +The data provider PHPUnit\TestFixture\Event\PrivateDataProviderTest::values specified for PHPUnit\TestFixture\Event\PrivateDataProviderTest::testSuccess is invalid +Data Provider method PHPUnit\TestFixture\Event\PrivateDataProviderTest::values() is not public +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\PrivateDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider-not-static.phpt b/tests/end-to-end/event/data-provider-not-static.phpt new file mode 100644 index 00000000000..dd1ee7fceba --- /dev/null +++ b/tests/end-to-end/event/data-provider-not-static.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that is not static +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DynamicDataProviderTest::values for test method PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess: +- PHPUnit\TestFixture\Event\DynamicDataProviderTest::values +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess) +The data provider PHPUnit\TestFixture\Event\DynamicDataProviderTest::values specified for PHPUnit\TestFixture\Event\DynamicDataProviderTest::testSuccess is invalid +Data Provider method PHPUnit\TestFixture\Event\DynamicDataProviderTest::values() is not static +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\DynamicDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/data-provider.phpt b/tests/end-to-end/event/data-provider.phpt new file mode 100644 index 00000000000..f50444ec77a --- /dev/null +++ b/tests/end-to-end/event/data-provider.phpt @@ -0,0 +1,38 @@ +--TEST-- +The right events are emitted in the right order for a successful test that uses a data provider +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\DataProviderTest::values for test method PHPUnit\TestFixture\Event\DataProviderTest::testSuccess) +Data Provider Method Finished for PHPUnit\TestFixture\Event\DataProviderTest::testSuccess: +- PHPUnit\TestFixture\Event\DataProviderTest::values +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderTest, 2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0) +Test Prepared (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0) +Test Passed (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0) +Test Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#0) +Test Preparation Started (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1) +Test Prepared (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1) +Test Passed (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1) +Test Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess#1) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderTest::testSuccess, 2 tests) +Test Suite Finished (PHPUnit\TestFixture\Event\DataProviderTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute-and-pattern.phpt b/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute-and-pattern.phpt new file mode 100644 index 00000000000..1fb255508be --- /dev/null +++ b/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute-and-pattern.phpt @@ -0,0 +1,28 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5532 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s + +..D. 4 / 4 (100%) + +Time: %s, Memory: %s MB + +1 test triggered 1 deprecation: + +1) %sIgnoreDeprecationsWithPatternTest.php:%d +baz + +OK, but there were issues! +Tests: 4, Assertions: 4, Deprecations: 1. diff --git a/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute.phpt b/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute.phpt new file mode 100644 index 00000000000..b0dc9e7b433 --- /dev/null +++ b/tests/end-to-end/event/deprecations-can-be-ignored-using-attribute.phpt @@ -0,0 +1,49 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5532 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOne, unknown if issue was triggered in first-party code or third-party code, ignored by test) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwo) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwo, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwo) +Test Finished (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOneErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOneErrorGetLast) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOneErrorGetLast, unknown if issue was triggered in first-party code or third-party code, ignored by test) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOneErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testOneErrorGetLast) +Test Preparation Started (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwoErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwoErrorGetLast) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwoErrorGetLast, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwoErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest::testTwoErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\IgnoreDeprecationsTest, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/duplicated-cli-options.phpt b/tests/end-to-end/event/duplicated-cli-options.phpt new file mode 100644 index 00000000000..02a599c5764 --- /dev/null +++ b/tests/end-to-end/event/duplicated-cli-options.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order when duplicated CLI options are used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Triggered Warning (Option --filter cannot be used more than once) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (0 tests) +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/error-handler-can-be-disabled.phpt b/tests/end-to-end/event/error-handler-can-be-disabled.phpt new file mode 100644 index 00000000000..f3609a41a2b --- /dev/null +++ b/tests/end-to-end/event/error-handler-can-be-disabled.phpt @@ -0,0 +1,47 @@ +--TEST-- +The right events are emitted in the right order when PHPUnit's error handler is disabled +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%s%esrc/Foo.php) +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (%s%ephpunit.xml, 4 tests) +Test Suite Started (default, 4 tests) +Test Suite Started (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodA) +Test Prepared (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodA) +Test Passed (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodA) +Test Finished (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodA) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodB) +Test Prepared (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodB) +Test Passed (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodB) +Test Finished (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testMethodB) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerSet) +Test Prepared (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerSet) +Test Passed (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerSet) +Test Finished (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerSet) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerIsNotSet) +Test Prepared (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerIsNotSet) +Test Passed (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerIsNotSet) +Test Finished (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest::testErrorHandlerIsNotSet) +Test Suite Finished (PHPUnit\TestFixture\Event\ErrorHandlerCanBeDisabled\FooTest, 4 tests) +Test Suite Finished (default, 4 tests) +Test Suite Finished (%s%ephpunit.xml, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/error.phpt b/tests/end-to-end/event/error.phpt new file mode 100644 index 00000000000..76a965154af --- /dev/null +++ b/tests/end-to-end/event/error.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for an errored test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ErrorTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\ErrorTest::testError) +Test Prepared (PHPUnit\TestFixture\Event\ErrorTest::testError) +Test Errored (PHPUnit\TestFixture\Event\ErrorTest::testError) +message +Test Finished (PHPUnit\TestFixture\Event\ErrorTest::testError) +Test Suite Finished (PHPUnit\TestFixture\Event\ErrorTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/exception-in-after-class-method.phpt b/tests/end-to-end/event/exception-in-after-class-method.phpt new file mode 100644 index 00000000000..668310abad9 --- /dev/null +++ b/tests/end-to-end/event/exception-in-after-class-method.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for when an exception is raised in tearDownAfterClass() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::testOne) +After Last Test Method Called (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::tearDownAfterClass) +After Last Test Method Errored (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::tearDownAfterClass) +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest::tearDownAfterClass +Test Suite Finished (PHPUnit\TestFixture\Event\ExceptionInTearDownAfterClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/exception-in-after-test-method.phpt b/tests/end-to-end/event/exception-in-after-test-method.phpt new file mode 100644 index 00000000000..4a38944c3d9 --- /dev/null +++ b/tests/end-to-end/event/exception-in-after-test-method.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for when an exception is raised in tearDown() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ExceptionInTearDownTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::testOne) +After Test Method Called (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::tearDown) +After Test Method Errored (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::tearDown) +After Test Method Finished: +- PHPUnit\TestFixture\Event\ExceptionInTearDownTest::tearDown +Test Errored (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\ExceptionInTearDownTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\ExceptionInTearDownTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/exception-in-before-class-method.phpt b/tests/end-to-end/event/exception-in-before-class-method.phpt new file mode 100644 index 00000000000..72278600bbb --- /dev/null +++ b/tests/end-to-end/event/exception-in-before-class-method.phpt @@ -0,0 +1,29 @@ +--TEST-- +The right events are emitted in the right order for when an exception is raised in setUpBeforeClass() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ExceptionInSetUpBeforeClassTest, 1 test) +Before First Test Method Called (PHPUnit\TestFixture\Event\ExceptionInSetUpBeforeClassTest::setUpBeforeClass) +Before First Test Method Errored (PHPUnit\TestFixture\Event\ExceptionInSetUpBeforeClassTest::setUpBeforeClass) +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\ExceptionInSetUpBeforeClassTest::setUpBeforeClass +Test Suite Finished (PHPUnit\TestFixture\Event\ExceptionInSetUpBeforeClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/exception-in-before-test-method.phpt b/tests/end-to-end/event/exception-in-before-test-method.phpt new file mode 100644 index 00000000000..48eb284df00 --- /dev/null +++ b/tests/end-to-end/event/exception-in-before-test-method.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for when an exception is raised in setUp() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\ExceptionInSetUpTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\ExceptionInSetUpTest::testOne) +Before Test Method Called (PHPUnit\TestFixture\Event\ExceptionInSetUpTest::setUp) +Before Test Method Errored (PHPUnit\TestFixture\Event\ExceptionInSetUpTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\ExceptionInSetUpTest::setUp +Test Preparation Errored (PHPUnit\TestFixture\Event\ExceptionInSetUpTest::testOne) +Test Errored (PHPUnit\TestFixture\Event\ExceptionInSetUpTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\ExceptionInSetUpTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/expectation-on-output.phpt b/tests/end-to-end/event/expectation-on-output.phpt new file mode 100644 index 00000000000..55c4d59cdad --- /dev/null +++ b/tests/end-to-end/event/expectation-on-output.phpt @@ -0,0 +1,39 @@ +--TEST-- +The right events are emitted in the right order for a test with an output expectation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\Issue445Test, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationBefore) +Test Prepared (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationBefore) +Test Passed (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationBefore) +Test Finished (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationBefore) +Test Preparation Started (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationAfter) +Test Prepared (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationAfter) +Test Passed (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationAfter) +Test Finished (PHPUnit\TestFixture\Issue445Test::testOutputWithExpectationAfter) +Test Preparation Started (PHPUnit\TestFixture\Issue445Test::testNotMatchingOutput) +Test Prepared (PHPUnit\TestFixture\Issue445Test::testNotMatchingOutput) +Test Failed (PHPUnit\TestFixture\Issue445Test::testNotMatchingOutput) +Failed asserting that two strings are identical. +Test Finished (PHPUnit\TestFixture\Issue445Test::testNotMatchingOutput) +Test Suite Finished (PHPUnit\TestFixture\Issue445Test, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/expected-and-unexpected-assertions.phpt b/tests/end-to-end/event/expected-and-unexpected-assertions.phpt new file mode 100644 index 00000000000..8dc28eea4ab --- /dev/null +++ b/tests/end-to-end/event/expected-and-unexpected-assertions.phpt @@ -0,0 +1,45 @@ +--TEST-- +The right events are emitted in the right order when a test that is not expected to perform assertions does not perform assertions and when a test that is not expected to perform assertions does perform assertions +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testTwo) +Test Passed (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testTwo) +Test Finished (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testThree) +Test Prepared (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testThree) +Test Passed (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testThree) +Test Considered Risky (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testThree) +This test is not expected to perform assertions but performed 1 assertion +Test Finished (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testFour) +Test Prepared (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testFour) +Test Passed (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testFour) +Test Considered Risky (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testFour) +This test is not expected to perform assertions but performed 1 assertion +Test Finished (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\Event\ExpectedAndUnexpectedAssertionsTest, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/failed-mock-expectation.phpt b/tests/end-to-end/event/failed-mock-expectation.phpt new file mode 100644 index 00000000000..cec67ead8ff --- /dev/null +++ b/tests/end-to-end/event/failed-mock-expectation.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a test with a failed expectation on a mock object +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\FailedExpectationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\FailedExpectationTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\FailedExpectationTest::testOne) +Mock Object Created (PHPUnit\TestFixture\MockObject\AnInterface) +Test Failed (PHPUnit\TestFixture\Event\FailedExpectationTest::testOne) +Expectation failed for method name is "doSomething" when invoked 1 time. +Method was expected to be called 1 time, actually called 0 times. +Test Finished (PHPUnit\TestFixture\Event\FailedExpectationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\FailedExpectationTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/incomplete-test.phpt b/tests/end-to-end/event/incomplete-test.phpt new file mode 100644 index 00000000000..f7fec9b8e58 --- /dev/null +++ b/tests/end-to-end/event/incomplete-test.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for an incomplete test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\IncompleteTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\IncompleteTest::testIncomplete) +Test Prepared (PHPUnit\TestFixture\Event\IncompleteTest::testIncomplete) +Test Marked Incomplete (PHPUnit\TestFixture\Event\IncompleteTest::testIncomplete) +message +Test Finished (PHPUnit\TestFixture\Event\IncompleteTest::testIncomplete) +Test Suite Finished (PHPUnit\TestFixture\Event\IncompleteTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/invalid-coverage-metadata.phpt b/tests/end-to-end/event/invalid-coverage-metadata.phpt new file mode 100644 index 00000000000..8c7418abb58 --- /dev/null +++ b/tests/end-to-end/event/invalid-coverage-metadata.phpt @@ -0,0 +1,48 @@ +--TEST-- +The right events are emitted in the right order for a test that has invalid code coverage metadata +--SKIPIF-- +run($_SERVER['argv']); +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::provider for test method PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne) +Data Provider Method Finished for PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne: +- PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne) +The data provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testOne is invalid +Data set #0 provided by PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::provider is invalid, expected array but got int +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testTwo) +Test Passed (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testTwo) +Test Finished (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\Event\InvalidDataProviderWithOneTestPassingTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/invalid-data-provider.phpt b/tests/end-to-end/event/invalid-data-provider.phpt new file mode 100644 index 00000000000..5f0aae6607a --- /dev/null +++ b/tests/end-to-end/event/invalid-data-provider.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a data provider that returns an invalid array +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Event\InvalidDataProviderTest::provider for test method PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne) +Data Provider Method Finished for PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne: +- PHPUnit\TestFixture\Event\InvalidDataProviderTest::provider +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne) +The data provider specified for PHPUnit\TestFixture\Event\InvalidDataProviderTest::testOne is invalid +Data set #0 provided by PHPUnit\TestFixture\Event\InvalidDataProviderTest::provider is invalid, expected array but got int +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Event\InvalidDataProviderTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/invalid-test-dependency.phpt b/tests/end-to-end/event/invalid-test-dependency.phpt new file mode 100644 index 00000000000..1c660608561 --- /dev/null +++ b/tests/end-to-end/event/invalid-test-dependency.phpt @@ -0,0 +1,29 @@ +--TEST-- +The right events are emitted in the right order for a test that has an invalid dependency +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\InvalidDependencyTest, 2 tests) +Test Errored (PHPUnit\TestFixture\Event\InvalidDependencyTest::testOne) +This test depends on "PHPUnit\TestFixture\Event\InvalidDependencyTest::doesNotExist" which does not exist +Test Errored (PHPUnit\TestFixture\Event\InvalidDependencyTest::testTwo) +This test depends on "DoesNotExist" which does not exist +Test Suite Finished (PHPUnit\TestFixture\Event\InvalidDependencyTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/invalid-version-constraint.phpt b/tests/end-to-end/event/invalid-version-constraint.phpt new file mode 100644 index 00000000000..ff04400590e --- /dev/null +++ b/tests/end-to-end/event/invalid-version-constraint.phpt @@ -0,0 +1,30 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6356 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Runner Triggered Warning (Test method PHPUnit\TestFixture\Event\InvalidVersionConstraintTest::testOne has attribute with version constraint string argument without explicit version comparison operator ("100"), version constraint is ignored) +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\InvalidVersionConstraintTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/missing-test-dependency.phpt b/tests/end-to-end/event/missing-test-dependency.phpt new file mode 100644 index 00000000000..6979f3d828c --- /dev/null +++ b/tests/end-to-end/event/missing-test-dependency.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a test that has a missing dependency +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\MissingDependencyTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\MissingDependencyTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\MissingDependencyTest::testOne) +Test Failed (PHPUnit\TestFixture\Event\MissingDependencyTest::testOne) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Event\MissingDependencyTest::testOne) +Test Skipped (PHPUnit\TestFixture\Event\MissingDependencyTest::testTwo) +This test depends on "PHPUnit\TestFixture\Event\MissingDependencyTest::testOne" to pass +Test Suite Finished (PHPUnit\TestFixture\Event\MissingDependencyTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt b/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt new file mode 100644 index 00000000000..69cf880d091 --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using the Mock Builder API and does not configure expectations but AllowMockObjectsWithoutExpectations is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Passed (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations.phpt b/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations.phpt new file mode 100644 index 00000000000..d93e2a85c1d --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-MockBuilder-without-expectations.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using the Mock Builder API and does not configure expectations +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest::testOne) +Test Triggered PHPUnit Notice (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest::testOne) +No expectations were configured for the mock object for PHPUnit\TestFixture\Event\Example. Consider refactoring your test code to use a test stub instead. The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check. +Test Passed (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\MockBuilderWithoutExpectationsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-class.phpt b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-class.phpt new file mode 100644 index 00000000000..8d298591cf4 --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-class.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using createMock() and does not configure expectations but AllowMockObjectsWithoutExpectations is used on test class +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest::testOne) +Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Passed (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-method.phpt b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-method.phpt new file mode 100644 index 00000000000..5b4f5a4b769 --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations-and-AllowMockObjectsWithoutExpectations-on-test-method.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using createMock() and does not configure expectations but AllowMockObjectsWithoutExpectations is used on test method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest::testOne) +Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Passed (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsOnMethodTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations.phpt b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations.phpt new file mode 100644 index 00000000000..8c7942709bb --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-createMock-without-expectations.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using createMock() and does not configure expectations +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest::testOne) +Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Triggered PHPUnit Notice (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest::testOne) +No expectations were configured for the mock object for PHPUnit\TestFixture\Event\Example. Consider refactoring your test code to use a test stub instead. The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check. +Test Passed (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\CreateMockWithoutExpectationsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt b/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt new file mode 100644 index 00000000000..7a3c9a243b9 --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations-and-AllowMockObjectsWithoutExpectations.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using createPartialMock() and does not configure expectations but AllowMockObjectsWithoutExpectations is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Partial Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Passed (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsAndAllowMockObjectsWithoutExpectationsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations.phpt b/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations.phpt new file mode 100644 index 00000000000..4a9bdcdad24 --- /dev/null +++ b/tests/end-to-end/event/mock-object-created-with-createPartialMock-without-expectations.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order for a test that creates a mock object using createPartialMock() and does not configure expectations +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest, 1 test) +Test Preparation Started (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest::testOne) +Test Prepared (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest::testOne) +Partial Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Triggered PHPUnit Notice (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest::testOne) +No expectations were configured for the mock object for PHPUnit\TestFixture\Event\Example. Consider refactoring your test code to use a test stub instead. The #[AllowMockObjectsWithoutExpectations] attribute can be used to opt out of this check. +Test Passed (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest::testOne) +Test Finished (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest::testOne) +Test Suite Finished (TestFixture\PHPUnit\Event\CreatePartialMockWithoutExpectationsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/mock-object.phpt b/tests/end-to-end/event/mock-object.phpt new file mode 100644 index 00000000000..a0067688e30 --- /dev/null +++ b/tests/end-to-end/event/mock-object.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a mock object +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\MockTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\MockTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\MockTest::testSuccess) +Mock Object Created (PHPUnit\TestFixture\Event\Example) +Test Passed (PHPUnit\TestFixture\Event\MockTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\MockTest::testSuccess) +Test Suite Finished (PHPUnit\TestFixture\Event\MockTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/php-deprecated.phpt b/tests/end-to-end/event/php-deprecated.phpt new file mode 100644 index 00000000000..ab649d45e98 --- /dev/null +++ b/tests/end-to-end/event/php-deprecated.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_DEPRECATED +--INI-- +error_reporting=-1 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature) +Test Prepared (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature) +Test Triggered PHP Deprecation (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature, unknown if issue was triggered in first-party code or third-party code) in %s:%d +strlen(): Passing null to parameter #1 ($string) of type string is deprecated +Test Triggered PHP Deprecation (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in %s:%d +strlen(): Passing null to parameter #1 ($string) of type string is deprecated +Test Passed (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature) +Test Finished (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest::testDeprecatedPhpFeature) +Test Suite Finished (PHPUnit\TestFixture\Event\DeprecatedPhpFeatureTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/php-notice.phpt b/tests/end-to-end/event/php-notice.phpt new file mode 100644 index 00000000000..e998541ec6c --- /dev/null +++ b/tests/end-to-end/event/php-notice.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_NOTICE +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\PhpNoticeTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice) +Test Prepared (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice) +Test Triggered PHP Notice (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice) in %s:%d +Only variables should be assigned by reference +Test Triggered PHP Notice (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice, suppressed using operator) in %s:%d +Only variables should be assigned by reference +Test Passed (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice) +Test Finished (PHPUnit\TestFixture\Event\PhpNoticeTest::testPhpNotice) +Test Suite Finished (PHPUnit\TestFixture\Event\PhpNoticeTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/php-warning.phpt b/tests/end-to-end/event/php-warning.phpt new file mode 100644 index 00000000000..cc312f7ff7e --- /dev/null +++ b/tests/end-to-end/event/php-warning.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_WARNING +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\PhpWarningTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning) +Test Prepared (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning) +Test Triggered PHP Warning (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning) in %s:%d +Undefined variable $b +Test Triggered PHP Warning (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning, suppressed using operator) in %s:%d +Undefined variable $b +Test Passed (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning) +Test Finished (PHPUnit\TestFixture\Event\PhpWarningTest::testPhpWarning) +Test Suite Finished (PHPUnit\TestFixture\Event\PhpWarningTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/phpt-clean-process-polluting.phpt b/tests/end-to-end/event/phpt-clean-process-polluting.phpt new file mode 100644 index 00000000000..a584b4a443f --- /dev/null +++ b/tests/end-to-end/event/phpt-clean-process-polluting.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a PHPT test with a CLEAN section which pollutes the process +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpt-clean-process-polluting.phpt, 1 test) +Test Preparation Started (%sphpt-clean-process-polluting.phpt) +Test Prepared (%sphpt-clean-process-polluting.phpt) +Child Process Started +Child Process Finished +Test Passed (%sphpt-clean-process-polluting.phpt) +Child Process Started +Child Process Finished +Test Finished (%sphpt-clean-process-polluting.phpt) +Test Suite Finished (%sphpt-clean-process-polluting.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-clean-with-io.phpt b/tests/end-to-end/event/phpt-clean-with-io.phpt new file mode 100644 index 00000000000..ab6f09d48b2 --- /dev/null +++ b/tests/end-to-end/event/phpt-clean-with-io.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a PHPT test with a CLEAN section which pollutes the process +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpt-clean-with-io.phpt, 1 test) +Test Preparation Started (%sphpt-clean-with-io.phpt) +Test Prepared (%sphpt-clean-with-io.phpt) +Child Process Started +Child Process Finished +Test Passed (%sphpt-clean-with-io.phpt) +Test Finished (%sphpt-clean-with-io.phpt) +Test Suite Finished (%sphpt-clean-with-io.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-clean.phpt b/tests/end-to-end/event/phpt-clean.phpt new file mode 100644 index 00000000000..f023db4ebaf --- /dev/null +++ b/tests/end-to-end/event/phpt-clean.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a PHPT test with a CLEAN section +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpt-clean.phpt, 1 test) +Test Preparation Started (%sphpt-clean.phpt) +Test Prepared (%sphpt-clean.phpt) +Child Process Started +Child Process Finished +Test Passed (%sphpt-clean.phpt) +Test Finished (%sphpt-clean.phpt) +Test Suite Finished (%sphpt-clean.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-ini-clean.phpt b/tests/end-to-end/event/phpt-ini-clean.phpt new file mode 100644 index 00000000000..06de7864d46 --- /dev/null +++ b/tests/end-to-end/event/phpt-ini-clean.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a PHPT test using a subprocess via --INI-- +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-ini-clean.phpt, 1 test) +Test Preparation Started (%s%ephpt-ini-clean.phpt) +Test Prepared (%s%ephpt-ini-clean.phpt) +Child Process Started +Child Process Finished +Test Passed (%sphpt-ini-clean.phpt) +Child Process Started +Child Process Finished +Test Finished (%s%ephpt-ini-clean.phpt) +Test Suite Finished (%s%ephpt-ini-clean.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-ini-subprocess.phpt b/tests/end-to-end/event/phpt-ini-subprocess.phpt new file mode 100644 index 00000000000..4231077f803 --- /dev/null +++ b/tests/end-to-end/event/phpt-ini-subprocess.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a PHPT test using a subprocess via --INI-- +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-ini-subprocess.phpt, 1 test) +Test Preparation Started (%s%ephpt-ini-subprocess.phpt) +Test Prepared (%s%ephpt-ini-subprocess.phpt) +Child Process Started +Child Process Finished +Child Process Started +Child Process Finished +Test Passed (%s%ephpt-ini-subprocess.phpt) +Test Finished (%s%ephpt-ini-subprocess.phpt) +Test Suite Finished (%s%ephpt-ini-subprocess.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-skipif-closing-php-tag.phpt b/tests/end-to-end/event/phpt-skipif-closing-php-tag.phpt new file mode 100644 index 00000000000..c4447974aba --- /dev/null +++ b/tests/end-to-end/event/phpt-skipif-closing-php-tag.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a skipped PHPT test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-skipif-closing-php-tag.phpt, 1 test) +Test Preparation Started (%s%ephpt-skipif-closing-php-tag.phpt) +Test Prepared (%s%ephpt-skipif-closing-php-tag.phpt) +Test Skipped (%s%ephpt-skipif-closing-php-tag.phpt) +something terrible happened +Test Finished (%s%ephpt-skipif-closing-php-tag.phpt) +Test Suite Finished (%s%ephpt-skipif-closing-php-tag.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-skipif-io.phpt b/tests/end-to-end/event/phpt-skipif-io.phpt new file mode 100644 index 00000000000..e16219bec76 --- /dev/null +++ b/tests/end-to-end/event/phpt-skipif-io.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for PHPT test using IO in skipif +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-skipif-io.phpt, 1 test) +Test Preparation Started (%s%ephpt-skipif-io.phpt) +Test Prepared (%s%ephpt-skipif-io.phpt) +Child Process Started +Child Process Finished +Test Passed (%s%ephpt-skipif-io.phpt) +Test Finished (%s%ephpt-skipif-io.phpt) +Test Suite Finished (%s%ephpt-skipif-io.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-skipif-require.phpt b/tests/end-to-end/event/phpt-skipif-require.phpt new file mode 100644 index 00000000000..aaf4a57a2f2 --- /dev/null +++ b/tests/end-to-end/event/phpt-skipif-require.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for PHPT test using require() in skipif +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-skipif-require.phpt, 1 test) +Test Preparation Started (%s%ephpt-skipif-require.phpt) +Test Prepared (%s%ephpt-skipif-require.phpt) +Child Process Started +Child Process Finished +Child Process Started +Child Process Finished +Test Passed (%s%ephpt-skipif-require.phpt) +Test Finished (%s%ephpt-skipif-require.phpt) +Test Suite Finished (%s%ephpt-skipif-require.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-skipif-subprocess.phpt b/tests/end-to-end/event/phpt-skipif-subprocess.phpt new file mode 100644 index 00000000000..e54c99c158d --- /dev/null +++ b/tests/end-to-end/event/phpt-skipif-subprocess.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a skipped PHPT test using a skipif subprocess +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-skipif-exit-subprocess.phpt, 1 test) +Test Preparation Started (%s%ephpt-skipif-exit-subprocess.phpt) +Test Prepared (%s%ephpt-skipif-exit-subprocess.phpt) +Child Process Started +Child Process Finished +Test Skipped (%s%ephpt-skipif-exit-subprocess.phpt) +is test +Test Finished (%s%ephpt-skipif-exit-subprocess.phpt) +Test Suite Finished (%s%ephpt-skipif-exit-subprocess.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpt-skipif.phpt b/tests/end-to-end/event/phpt-skipif.phpt new file mode 100644 index 00000000000..f3bb2853bed --- /dev/null +++ b/tests/end-to-end/event/phpt-skipif.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a skipped PHPT test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%ephpt-skipif-location-hint-example.phpt, 1 test) +Test Preparation Started (%s%ephpt-skipif-location-hint-example.phpt) +Test Prepared (%s%ephpt-skipif-location-hint-example.phpt) +Test Skipped (%s%ephpt-skipif-location-hint-example.phpt) +something terrible happened +Test Finished (%s%ephpt-skipif-location-hint-example.phpt) +Test Suite Finished (%s%ephpt-skipif-location-hint-example.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpunit-deprecated-ignored.phpt b/tests/end-to-end/event/phpunit-deprecated-ignored.phpt new file mode 100644 index 00000000000..d7f36d52076 --- /dev/null +++ b/tests/end-to-end/event/phpunit-deprecated-ignored.phpt @@ -0,0 +1,29 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a deprecated PHPUnit feature when PHPUnit deprecations are ignored using attribute +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Prepared (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Passed (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Finished (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Suite Finished (PHPUnit\TestFixture\Event\IgnoredDeprecatedPhpunitFeatureTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpunit-deprecated.phpt b/tests/end-to-end/event/phpunit-deprecated.phpt new file mode 100644 index 00000000000..42b74026e6e --- /dev/null +++ b/tests/end-to-end/event/phpunit-deprecated.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a deprecated PHPUnit feature +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Prepared (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Triggered PHPUnit Deprecation (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +message +Test Passed (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Finished (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest::testDeprecatedPhpunitFeature) +Test Suite Finished (PHPUnit\TestFixture\Event\DeprecatedPhpunitFeatureTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpunit-notice.phpt b/tests/end-to-end/event/phpunit-notice.phpt new file mode 100644 index 00000000000..d38ca29310c --- /dev/null +++ b/tests/end-to-end/event/phpunit-notice.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_WARNING +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\PhpunitNoticeTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\PhpunitNoticeTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\PhpunitNoticeTest::testOne) +Test Triggered PHPUnit Notice (PHPUnit\TestFixture\Event\PhpunitNoticeTest::testOne) +message +Test Runner Triggered Notice (message) +Test Passed (PHPUnit\TestFixture\Event\PhpunitNoticeTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\PhpunitNoticeTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\PhpunitNoticeTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/phpunit-warning-ignored.phpt b/tests/end-to-end/event/phpunit-warning-ignored.phpt new file mode 100644 index 00000000000..ece9832ac60 --- /dev/null +++ b/tests/end-to-end/event/phpunit-warning-ignored.phpt @@ -0,0 +1,29 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers a PHPUnit warning +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +....W. 6 / 6 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\Event\PhpunitWarningIgnoredTest::testPhpunitWarningWithWrongPattern +another message + +%sPhpunitWarningIgnoredTest.php:%d + +OK, but there were issues! +Tests: 6, Assertions: 6, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/event/phpunit-warning.phpt b/tests/end-to-end/event/phpunit-warning.phpt new file mode 100644 index 00000000000..c21366a43da --- /dev/null +++ b/tests/end-to-end/event/phpunit-warning.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers a PHPUnit warning +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\PhpunitWarningTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\PhpunitWarningTest::testPhpunitWarning) +Test Prepared (PHPUnit\TestFixture\Event\PhpunitWarningTest::testPhpunitWarning) +Test Triggered PHPUnit Warning (PHPUnit\TestFixture\Event\PhpunitWarningTest::testPhpunitWarning) +message +Test Passed (PHPUnit\TestFixture\Event\PhpunitWarningTest::testPhpunitWarning) +Test Finished (PHPUnit\TestFixture\Event\PhpunitWarningTest::testPhpunitWarning) +Test Suite Finished (PHPUnit\TestFixture\Event\PhpunitWarningTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/process-isolation-disable-xdebug.phpt b/tests/end-to-end/event/process-isolation-disable-xdebug.phpt new file mode 100644 index 00000000000..a3dbefafb1f --- /dev/null +++ b/tests/end-to-end/event/process-isolation-disable-xdebug.phpt @@ -0,0 +1,40 @@ +--TEST-- +Subprocesses auto-disable xdebug when no debugger is attached. +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\XdebugIsDisabled, 1 test) +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\XdebugIsDisabled::testOne) +Test Prepared (PHPUnit\TestFixture\Event\XdebugIsDisabled::testOne) +Test Passed (PHPUnit\TestFixture\Event\XdebugIsDisabled::testOne) +Test Finished (PHPUnit\TestFixture\Event\XdebugIsDisabled::testOne) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Event\XdebugIsDisabled, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/process-isolation-fatal.phpt b/tests/end-to-end/event/process-isolation-fatal.phpt new file mode 100644 index 00000000000..f3d71d320a4 --- /dev/null +++ b/tests/end-to-end/event/process-isolation-fatal.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that is run in process isolation and triggers a fatal error +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\FatalTest, 1 test) +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\FatalTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\FatalTest::testOne) +Test Errored (PHPUnit\TestFixture\Event\FatalTest::testOne) +Call to undefined function PHPUnit\TestFixture\Event\doesNotExist() +Test Finished (PHPUnit\TestFixture\Event\FatalTest::testOne) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Event\FatalTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/registered-failure-interface.phpt b/tests/end-to-end/event/registered-failure-interface.phpt new file mode 100644 index 00000000000..d05df537573 --- /dev/null +++ b/tests/end-to-end/event/registered-failure-interface.phpt @@ -0,0 +1,38 @@ +--TEST-- +The right events are emitted in the right order for a test that registers a failure interface +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sbootstrap.php) +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne) +Test Failed (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne) +this should be treated as a failure +Test Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo) +Test Prepared (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo) +Test Errored (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo) +this should be treated as an error +Test Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\Event\CustomFailureInterfaceTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/risky-code-coverage.phpt b/tests/end-to-end/event/risky-code-coverage.phpt new file mode 100644 index 00000000000..afba83956a7 --- /dev/null +++ b/tests/end-to-end/event/risky-code-coverage.phpt @@ -0,0 +1,48 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it executed code that is not listed as code to be covered or used +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Static Analysis for Code Coverage Started +Static Analysis for Code Coverage Finished (%d cache hits, %d cache misses) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest::testSomething) +Test Prepared (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest::testSomething) +Test Passed (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest::testSomething) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest::testSomething) +This test executed code that is not listed as code to be covered or used: +- PHPUnit\TestFixture\Event\RiskyCodeCoverage\Bar + +Test Finished (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest::testSomething) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyCodeCoverage\FooTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-depends-on-larger-test.phpt b/tests/end-to-end/event/risky-depends-on-larger-test.phpt new file mode 100644 index 00000000000..42ae306fdac --- /dev/null +++ b/tests/end-to-end/event/risky-depends-on-larger-test.phpt @@ -0,0 +1,39 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it depends on a larger test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (CLI Arguments, 2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\LargeTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest, 1 test) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest::testOne) +This test depends on a test that is larger than itself +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseDependencyOnLargerTest\SmallTest, 1 test) +Test Suite Finished (CLI Arguments, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-global-state-modification.phpt b/tests/end-to-end/event/risky-global-state-modification.phpt new file mode 100644 index 00000000000..c166d6aacdb --- /dev/null +++ b/tests/end-to-end/event/risky-global-state-modification.phpt @@ -0,0 +1,39 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it modified global state +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest::testOne) +This test modified global state but was not expected to do so +--- Global variables before the test ++++ Global variables after the test +%A ++ 'variable' => 'value', +%A +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseGlobalStateModificationTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-no-assertions-isolation.phpt b/tests/end-to-end/event/risky-no-assertions-isolation.phpt new file mode 100644 index 00000000000..93390874eaa --- /dev/null +++ b/tests/end-to-end/event/risky-no-assertions-isolation.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that is run in an isolated process and is considered risky because it did not perform assertions +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest, 1 test) +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-no-assertions.phpt b/tests/end-to-end/event/risky-no-assertions.phpt new file mode 100644 index 00000000000..e42b0c0110c --- /dev/null +++ b/tests/end-to-end/event/risky-no-assertions.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it did not perform assertions +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseNoAssertionsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-output.phpt b/tests/end-to-end/event/risky-output.phpt new file mode 100644 index 00000000000..387cdb97731 --- /dev/null +++ b/tests/end-to-end/event/risky-output.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it prints output +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest::testOne) +Test Printed Unexpected Output +* +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest::testOne) +Test code or tested code printed unexpected output: * +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseOutputTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-time-limit-exceeded.phpt b/tests/end-to-end/event/risky-time-limit-exceeded.phpt new file mode 100644 index 00000000000..c78d6cc73e1 --- /dev/null +++ b/tests/end-to-end/event/risky-time-limit-exceeded.phpt @@ -0,0 +1,34 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky because it timed out +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest::testOne) +This test was aborted after 1 second +Test Finished (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyBecauseTimeLimitExceededTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/risky-with-multiple-reasons.phpt b/tests/end-to-end/event/risky-with-multiple-reasons.phpt new file mode 100644 index 00000000000..60d01435d6d --- /dev/null +++ b/tests/end-to-end/event/risky-with-multiple-reasons.phpt @@ -0,0 +1,40 @@ +--TEST-- +The right events are emitted in the right order for a test that is considered risky for multiple reasons +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +Test Passed (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +This test modified global state but was not expected to do so +--- Global variables before the test ++++ Global variables after the test +%A ++ 'variable' => 'value', +%A +Test Considered Risky (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +This test did not perform any assertions +Test Finished (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\RiskyWithMultipleReasonsTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/success-process-isolation.phpt b/tests/end-to-end/event/success-process-isolation.phpt new file mode 100644 index 00000000000..7b4f2368adc --- /dev/null +++ b/tests/end-to-end/event/success-process-isolation.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a successful test that is run in an isolated process +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Passed (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/success-verbose.phpt b/tests/end-to-end/event/success-verbose.phpt new file mode 100644 index 00000000000..2f7ba5ed546 --- /dev/null +++ b/tests/end-to-end/event/success-verbose.phpt @@ -0,0 +1,37 @@ +--TEST-- +The right events are emitted in the right order for a successful test with extended information +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($traceFile); + +unlink($traceFile); +--EXPECTF-- +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Started (PHPUnit %s using %s) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Configured +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Event Facade Sealed +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Loaded (1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Started +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Sorted +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Started (1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Started (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Finished (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/success.phpt b/tests/end-to-end/event/success.phpt new file mode 100644 index 00000000000..c326766b72e --- /dev/null +++ b/tests/end-to-end/event/success.phpt @@ -0,0 +1,29 @@ +--TEST-- +The right events are emitted in the right order for a successful test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Passed (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Suite Finished (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/successful-mock-expectation.phpt b/tests/end-to-end/event/successful-mock-expectation.phpt new file mode 100644 index 00000000000..1f7d881f420 --- /dev/null +++ b/tests/end-to-end/event/successful-mock-expectation.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test with a successful expectation on a mock object +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SuccessfulExpectationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\SuccessfulExpectationTest::testOne) +Test Prepared (PHPUnit\TestFixture\Event\SuccessfulExpectationTest::testOne) +Mock Object Created (PHPUnit\TestFixture\MockObject\AnInterface) +Test Passed (PHPUnit\TestFixture\Event\SuccessfulExpectationTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\SuccessfulExpectationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\SuccessfulExpectationTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/suppressed-user-notice.phpt b/tests/end-to-end/event/suppressed-user-notice.phpt new file mode 100644 index 00000000000..192513d5b95 --- /dev/null +++ b/tests/end-to-end/event/suppressed-user-notice.phpt @@ -0,0 +1,37 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers a suppressed E_USER_NOTICE +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNotice) +Test Prepared (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNotice) +Test Triggered Notice (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNotice, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNotice) +Test Finished (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNotice) +Test Preparation Started (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNoticeErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNoticeErrorGetLast) +Test Triggered Notice (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNoticeErrorGetLast, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNoticeErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest::testSuppressedUserNoticeErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\SuppressedUserNoticeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/suppressed-user-warning.phpt b/tests/end-to-end/event/suppressed-user-warning.phpt new file mode 100644 index 00000000000..68906bd5b28 --- /dev/null +++ b/tests/end-to-end/event/suppressed-user-warning.phpt @@ -0,0 +1,37 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers a suppressed E_USER_WARNING +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\SuppressedUserWarningTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarning) +Test Prepared (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarning) +Test Triggered Warning (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarning, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarning) +Test Finished (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarning) +Test Preparation Started (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarningErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarningErrorGetLast) +Test Triggered Warning (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarningErrorGetLast, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarningErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\SuppressedUserWarningTest::testSuppressedUserWarningErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\SuppressedUserWarningTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/template-methods-isolation.phpt b/tests/end-to-end/event/template-methods-isolation.phpt new file mode 100644 index 00000000000..ea1761f95c7 --- /dev/null +++ b/tests/end-to-end/event/template-methods-isolation.phpt @@ -0,0 +1,80 @@ +--TEST-- +The right events are emitted in the right order for the template methods of a test class that is run in process isolation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\TemplateMethodsTest, 2 tests) +Before First Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass) +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Before First Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass) +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass +Before Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp +Pre Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions) +Pre Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions +Test Prepared (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Post Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions) +Post Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions +After Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown) +After Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown +After Last Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass) +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass +Test Passed (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Before First Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass) +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass +Before Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp +Pre Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions) +Pre Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions +Test Prepared (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Post Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions) +Post Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions +After Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown) +After Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown +After Last Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass) +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass +Test Passed (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Test Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Child Process Finished +After Last Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass) +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass +Test Suite Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/template-methods.phpt b/tests/end-to-end/event/template-methods.phpt new file mode 100644 index 00000000000..ab5df524a8d --- /dev/null +++ b/tests/end-to-end/event/template-methods.phpt @@ -0,0 +1,63 @@ +--TEST-- +The right events are emitted in the right order for the template methods of a test class +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\TemplateMethodsTest, 2 tests) +Before First Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass) +Before First Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUpBeforeClass +Test Preparation Started (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Before Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp +Pre Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions) +Pre Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions +Test Prepared (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Post Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions) +Post Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions +After Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown) +After Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown +Test Passed (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Test Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Before Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::setUp +Pre Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions) +Pre Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPreConditions +Test Prepared (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Post Condition Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions) +Post Condition Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::assertPostConditions +After Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown) +After Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDown +Test Passed (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +Test Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest::testTwo) +After Last Test Method Called (PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass) +After Last Test Method Finished: +- PHPUnit\TestFixture\Event\TemplateMethodsTest::tearDownAfterClass +Test Suite Finished (PHPUnit\TestFixture\Event\TemplateMethodsTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/test-method-builder-cannot-find-testcase-object.phpt b/tests/end-to-end/event/test-method-builder-cannot-find-testcase-object.phpt new file mode 100644 index 00000000000..297aa8eb02d --- /dev/null +++ b/tests/end-to-end/event/test-method-builder-cannot-find-testcase-object.phpt @@ -0,0 +1,15 @@ +--TEST-- +The right exception is raised when TestMethodBuilder::fromCallStack() cannot find a TestCase object +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SkippedInSetupBeforeClassTest, 1 test) +Before First Test Method Called (PHPUnit\TestFixture\Event\SkippedInSetupBeforeClassTest::setUpBeforeClass) +Test Suite Skipped (PHPUnit\TestFixture\Event\SkippedInSetupBeforeClassTest, message) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/test-skipped-in-setup.phpt b/tests/end-to-end/event/test-skipped-in-setup.phpt new file mode 100644 index 00000000000..aa6bc9806f9 --- /dev/null +++ b/tests/end-to-end/event/test-skipped-in-setup.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a test skipped in setUp() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SkippedInSetupTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\SkippedInSetupTest::testOne) +Before Test Method Called (PHPUnit\TestFixture\Event\SkippedInSetupTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Event\SkippedInSetupTest::setUp +Test Skipped (PHPUnit\TestFixture\Event\SkippedInSetupTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\SkippedInSetupTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/test-skipped.phpt b/tests/end-to-end/event/test-skipped.phpt new file mode 100644 index 00000000000..7d3f68453d4 --- /dev/null +++ b/tests/end-to-end/event/test-skipped.phpt @@ -0,0 +1,30 @@ +--TEST-- +The right events are emitted in the right order for a skipped test +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SkippedTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\SkippedTest::testSkipped) +Test Prepared (PHPUnit\TestFixture\Event\SkippedTest::testSkipped) +Test Skipped (PHPUnit\TestFixture\Event\SkippedTest::testSkipped) +message +Test Finished (PHPUnit\TestFixture\Event\SkippedTest::testSkipped) +Test Suite Finished (PHPUnit\TestFixture\Event\SkippedTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/test-stub.phpt b/tests/end-to-end/event/test-stub.phpt new file mode 100644 index 00000000000..9a2667b567b --- /dev/null +++ b/tests/end-to-end/event/test-stub.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a test stub +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sExample.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\StubTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\StubTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\StubTest::testSuccess) +Test Stub Created (PHPUnit\TestFixture\Event\Example) +Test Passed (PHPUnit\TestFixture\Event\StubTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\StubTest::testSuccess) +Test Suite Finished (PHPUnit\TestFixture\Event\StubTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/testwith-attribute-too-many-values.phpt b/tests/end-to-end/event/testwith-attribute-too-many-values.phpt new file mode 100644 index 00000000000..6255dd60b25 --- /dev/null +++ b/tests/end-to-end/event/testwith-attribute-too-many-values.phpt @@ -0,0 +1,33 @@ +--TEST-- +The right events are emitted in the right order for a successful test that uses a TestWith attribute which provides more values than the test method accepts +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Triggered PHPUnit Warning (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne) +Data set #0 provided by TestWith#0 attribute has more arguments (3) than the test method accepts (2) +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0) +Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0) +Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0) +Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne#0) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest::testOne, 1 test) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTooManyValuesTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/testwith-attribute.phpt b/tests/end-to-end/event/testwith-attribute.phpt new file mode 100644 index 00000000000..d5761afdc7c --- /dev/null +++ b/tests/end-to-end/event/testwith-attribute.phpt @@ -0,0 +1,49 @@ +--TEST-- +The right events are emitted in the right order for a successful test that uses the TestWith and TestWithJson attributes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest, 4 tests) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0) +Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0) +Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0) +Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne#0) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOne, 1 test) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1) +Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1) +Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1) +Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName#Name1) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testOneWithName, 1 test) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0) +Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0) +Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0) +Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo#0) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwo, 1 test) +Test Suite Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2) +Test Prepared (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2) +Test Passed (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2) +Test Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName#Name2) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest::testTwoWithName, 1 test) +Test Suite Finished (PHPUnit\TestFixture\Metadata\Attribute\TestWithTest, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/testwithjson-attribute-invalid-value.phpt b/tests/end-to-end/event/testwithjson-attribute-invalid-value.phpt new file mode 100644 index 00000000000..e7c4825b1af --- /dev/null +++ b/tests/end-to-end/event/testwithjson-attribute-invalid-value.phpt @@ -0,0 +1,27 @@ +--TEST-- +The right events are emitted in the right order for a test that uses a TestWithJson attribute which provides an invalid value +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Triggered PHPUnit Error (PHPUnit\TestFixture\Metadata\Attribute\TestWithInvalidValueTest::testOne) +The data provider specified for PHPUnit\TestFixture\Metadata\Attribute\TestWithInvalidValueTest::testOne is invalid +Data set #0 provided by TestWith#0 attribute is invalid, expected array but got bool +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\Metadata\Attribute\TestWithInvalidValueTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/too-few-columns.phpt b/tests/end-to-end/event/too-few-columns.phpt new file mode 100644 index 00000000000..2b7ee09d69f --- /dev/null +++ b/tests/end-to-end/event/too-few-columns.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order when too few columns are requested +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Triggered Warning (Less than 16 columns requested, number of columns set to 16) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Prepared (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Passed (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Finished (PHPUnit\TestFixture\Event\SuccessTest::testSuccess) +Test Suite Finished (PHPUnit\TestFixture\Event\SuccessTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/event/unexpected-end-of-test-in-separate-process.phpt b/tests/end-to-end/event/unexpected-end-of-test-in-separate-process.phpt new file mode 100644 index 00000000000..e36dce48333 --- /dev/null +++ b/tests/end-to-end/event/unexpected-end-of-test-in-separate-process.phpt @@ -0,0 +1,31 @@ +--TEST-- +The right events are emitted in the right order for a test run in a separate process that ends unexpectedly +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\SeparateProcessesTest, 1 test) +Child Process Started +Child Process Errored +Test Errored (PHPUnit\TestFixture\Event\SeparateProcessesTest::testOne) +Test was run in child process and ended unexpectedly +Test Finished (PHPUnit\TestFixture\Event\SeparateProcessesTest::testOne) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Event\SeparateProcessesTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/unsatisfied-requirement-before-class-method.phpt b/tests/end-to-end/event/unsatisfied-requirement-before-class-method.phpt new file mode 100644 index 00000000000..b573fdf50b5 --- /dev/null +++ b/tests/end-to-end/event/unsatisfied-requirement-before-class-method.phpt @@ -0,0 +1,25 @@ +--TEST-- +The right events are emitted in the right order for a test that has an unsatisfied requirement (before class method) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\UnsatisfiedRequirementBeforeClassMethodTest, 1 test) +Test Suite Skipped (PHPUnit\TestFixture\Event\UnsatisfiedRequirementBeforeClassMethodTest, PHP ^100.0 is required.) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/unsatisfied-requirement-class.phpt b/tests/end-to-end/event/unsatisfied-requirement-class.phpt new file mode 100644 index 00000000000..6ed218e86b6 --- /dev/null +++ b/tests/end-to-end/event/unsatisfied-requirement-class.phpt @@ -0,0 +1,28 @@ +--TEST-- +The right events are emitted in the right order for a test that has an unsatisfied requirement (class level) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\UnsatisfiedRequirementClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\UnsatisfiedRequirementClassTest::testOne) +Test Skipped (PHPUnit\TestFixture\Event\UnsatisfiedRequirementClassTest::testOne) +PHP ^100.0 is required. +Test Suite Finished (PHPUnit\TestFixture\Event\UnsatisfiedRequirementClassTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/unsatisfied-requirement-method.phpt b/tests/end-to-end/event/unsatisfied-requirement-method.phpt new file mode 100644 index 00000000000..034a7f6fb04 --- /dev/null +++ b/tests/end-to-end/event/unsatisfied-requirement-method.phpt @@ -0,0 +1,28 @@ +--TEST-- +The right events are emitted in the right order for a test that has an unsatisfied requirement (method level) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Event\UnsatisfiedRequirementMethodTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\UnsatisfiedRequirementMethodTest::testOne) +Test Skipped (PHPUnit\TestFixture\Event\UnsatisfiedRequirementMethodTest::testOne) +PHP ^100.0 is required. +Test Suite Finished (PHPUnit\TestFixture\Event\UnsatisfiedRequirementMethodTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/user-deprecated.phpt b/tests/end-to-end/event/user-deprecated.phpt new file mode 100644 index 00000000000..b12840e4ce5 --- /dev/null +++ b/tests/end-to-end/event/user-deprecated.phpt @@ -0,0 +1,39 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\DeprecatedFeatureTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature) +Test Prepared (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature, unknown if issue was triggered in first-party code or third-party code) in %s:%d +message +Test Triggered Deprecation (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature) +Test Finished (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedFeature) +Test Preparation Started (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedSuppressedErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedSuppressedErrorGetLast) +Test Triggered Deprecation (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedSuppressedErrorGetLast, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedSuppressedErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\DeprecatedFeatureTest::testDeprecatedSuppressedErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\DeprecatedFeatureTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/user-error-php-84.phpt b/tests/end-to-end/event/user-error-php-84.phpt new file mode 100644 index 00000000000..58d909979b1 --- /dev/null +++ b/tests/end-to-end/event/user-error-php-84.phpt @@ -0,0 +1,48 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_ERROR +--SKIPIF-- +')) { + print 'skip: PHP 8.4 is required.'; +} +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\UserErrorTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Prepared (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Triggered PHP Deprecation (PHPUnit\TestFixture\Event\UserErrorTest::testUserError, unknown if issue was triggered in first-party code or third-party code) in %s:%d +Passing E_USER_ERROR to trigger_error() is deprecated since 8.4, throw an exception or call exit with a string message instead +Test Triggered Error (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) in %s:%d +message +Test Errored (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +E_USER_ERROR was triggered +Test Finished (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Preparation Started (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Prepared (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Triggered PHP Deprecation (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution, unknown if issue was triggered in first-party code or third-party code) in %s:%d +Passing E_USER_ERROR to trigger_error() is deprecated since 8.4, throw an exception or call exit with a string message instead +Test Triggered Error (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) in %s:%d +message +Test Errored (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +E_USER_ERROR was triggered +Test Finished (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Suite Finished (PHPUnit\TestFixture\Event\UserErrorTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/user-error.phpt b/tests/end-to-end/event/user-error.phpt new file mode 100644 index 00000000000..2212f04504b --- /dev/null +++ b/tests/end-to-end/event/user-error.phpt @@ -0,0 +1,44 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_ERROR +--SKIPIF-- +=')) { + print 'skip: PHP < 8.4 is required.'; +} +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\UserErrorTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Prepared (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Triggered Error (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) in %s:%d +message +Test Errored (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +E_USER_ERROR was triggered +Test Finished (PHPUnit\TestFixture\Event\UserErrorTest::testUserError) +Test Preparation Started (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Prepared (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Triggered Error (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) in %s:%d +message +Test Errored (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +E_USER_ERROR was triggered +Test Finished (PHPUnit\TestFixture\Event\UserErrorTest::testUserErrorMustAbortExecution) +Test Suite Finished (PHPUnit\TestFixture\Event\UserErrorTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/event/user-notice.phpt b/tests/end-to-end/event/user-notice.phpt new file mode 100644 index 00000000000..8b2ba0e0b2d --- /dev/null +++ b/tests/end-to-end/event/user-notice.phpt @@ -0,0 +1,37 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers an E_USER_NOTICE +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\UserNoticeTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNotice) +Test Prepared (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNotice) +Test Triggered Notice (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNotice) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNotice) +Test Finished (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNotice) +Test Preparation Started (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNoticeErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNoticeErrorGetLast) +Test Triggered Notice (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNoticeErrorGetLast) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNoticeErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\UserNoticeTest::testUserNoticeErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\UserNoticeTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/event/user-warning.phpt b/tests/end-to-end/event/user-warning.phpt new file mode 100644 index 00000000000..a43703d3f85 --- /dev/null +++ b/tests/end-to-end/event/user-warning.phpt @@ -0,0 +1,37 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_WARNING +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Event\UserWarningTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarning) +Test Prepared (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarning) +Test Triggered Warning (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarning) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarning) +Test Finished (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarning) +Test Preparation Started (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarningErrorGetLast) +Test Prepared (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarningErrorGetLast) +Test Triggered Warning (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarningErrorGetLast) in %s:%d +message +Test Passed (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarningErrorGetLast) +Test Finished (PHPUnit\TestFixture\Event\UserWarningTest::testUserWarningErrorGetLast) +Test Suite Finished (PHPUnit\TestFixture\Event\UserWarningTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/empty-test-suite.phpt b/tests/end-to-end/execution-order/empty-test-suite.phpt new file mode 100644 index 00000000000..9bfa11f43fe --- /dev/null +++ b/tests/end-to-end/execution-order/empty-test-suite.phpt @@ -0,0 +1,24 @@ +--TEST-- +Empty test suite +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Runner Triggered Warning (No tests found in class "PHPUnit\TestFixture\ExecutionOrder\EmptyTestSuite\FooTest".) +Test Suite Loaded (0 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (0 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/execution-order/fixture/empty-test-suite/FooTest.php b/tests/end-to-end/execution-order/fixture/empty-test-suite/FooTest.php new file mode 100644 index 00000000000..b322b22fc4f --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/empty-test-suite/FooTest.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\EmptyTestSuite; + +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BarTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BarTest.php new file mode 100644 index 00000000000..d78e1c5d2aa --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BarTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Defects; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +#[CoversNothing] +final class BarTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(false); + } + + public function testThree(): void + { + throw new RuntimeException('message'); + } + + public function testFour(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BazTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BazTest.php new file mode 100644 index 00000000000..4325f660cfb --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/BazTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Defects; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +#[CoversNothing] +final class BazTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(false); + } + + public function testThree(): void + { + throw new RuntimeException('message'); + } + + public function testFour(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-defects/test-results b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/test-results new file mode 100644 index 00000000000..0939ed3671f --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-defects/test-results @@ -0,0 +1 @@ +{"version":2,"defects":{"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testTwo":7,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testThree":8,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testTwo":7,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testThree":8},"times":{"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testOne":0.002,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testTwo":0.003,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testThree":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BarTest::testFour":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testOne":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testTwo":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testThree":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\BazTest::testFour":0}} \ No newline at end of file diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/EndToEndTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/EndToEndTest.php new file mode 100644 index 00000000000..e44d7da4196 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/EndToEndTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\DifferentSizes; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\TestCase; + +#[Large] +#[CoversNothing] +final class EndToEndTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/IntegrationTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/IntegrationTest.php new file mode 100644 index 00000000000..912cceb656c --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/IntegrationTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\DifferentSizes; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; + +#[Medium] +#[CoversNothing] +final class IntegrationTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/UnitTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/UnitTest.php new file mode 100644 index 00000000000..04130056b04 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-different-sizes/UnitTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\DifferentSizes; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[Small] +#[CoversNothing] +final class UnitTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-duration/BarTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/BarTest.php new file mode 100644 index 00000000000..7639d2ba51d --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/BarTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Duration; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class BarTest extends TestCase +{ + public function testOne(): void + { + // sleep(6); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + // sleep(1); + + $this->assertTrue(true); + } + + public function testThree(): void + { + // sleep(5); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-duration/FooTest.php b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/FooTest.php new file mode 100644 index 00000000000..52a6244dc1d --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/FooTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Duration; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class FooTest extends TestCase +{ + public function testOne(): void + { + // sleep(3); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + // sleep(4); + + $this->assertTrue(true); + } + + public function testThree(): void + { + // sleep(2); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes-with-duration/test-results b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/test-results new file mode 100644 index 00000000000..088148bd071 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes-with-duration/test-results @@ -0,0 +1 @@ +{"version":2,"defects":[],"times":{"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\BarTest::testOne":6.013,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\BarTest::testTwo":1.001,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\BarTest::testThree":5.001,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testOne":3.001,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testTwo":4.002,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testThree":2.001}} \ No newline at end of file diff --git a/tests/end-to-end/execution-order/fixture/test-classes/BarTest.php b/tests/end-to-end/execution-order/fixture/test-classes/BarTest.php new file mode 100644 index 00000000000..d0294712f5d --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes/BarTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class BarTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-classes/FooTest.php b/tests/end-to-end/execution-order/fixture/test-classes/FooTest.php new file mode 100644 index 00000000000..e4180f5461f --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-classes/FooTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class FooTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-methods-with-defects/FooTest.php b/tests/end-to-end/execution-order/fixture/test-methods-with-defects/FooTest.php new file mode 100644 index 00000000000..7617de2e0bb --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-methods-with-defects/FooTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Defects; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +#[CoversNothing] +final class FooTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(false); + } + + public function testThree(): void + { + throw new RuntimeException('message'); + } + + public function testFour(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-methods-with-defects/test-results b/tests/end-to-end/execution-order/fixture/test-methods-with-defects/test-results new file mode 100644 index 00000000000..eb8ac71fc22 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-methods-with-defects/test-results @@ -0,0 +1 @@ +{"version":2,"defects":{"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testTwo":7,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testThree":8},"times":{"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testOne":0,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testTwo":0.001,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testThree":0.004,"PHPUnit\\TestFixture\\ExecutionOrder\\Defects\\FooTest::testFour":0}} \ No newline at end of file diff --git a/tests/end-to-end/execution-order/fixture/test-methods-with-dependencies/FooTest.php b/tests/end-to-end/execution-order/fixture/test-methods-with-dependencies/FooTest.php new file mode 100644 index 00000000000..d0111c51d45 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-methods-with-dependencies/FooTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Dependencies; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class FooTest extends TestCase +{ + #[Depends('testTwo')] + public function testOne(): void + { + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-methods-with-duration/FooTest.php b/tests/end-to-end/execution-order/fixture/test-methods-with-duration/FooTest.php new file mode 100644 index 00000000000..74235f240fe --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-methods-with-duration/FooTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExecutionOrder\Duration; + +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +final class FooTest extends TestCase +{ + public function testOne(): void + { + // sleep(3); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + // sleep(1); + + $this->assertTrue(true); + } + + public function testThree(): void + { + // sleep(2); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/execution-order/fixture/test-methods-with-duration/test-results b/tests/end-to-end/execution-order/fixture/test-methods-with-duration/test-results new file mode 100644 index 00000000000..81a447ed668 --- /dev/null +++ b/tests/end-to-end/execution-order/fixture/test-methods-with-duration/test-results @@ -0,0 +1 @@ +{"version":2,"defects":[],"times":{"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testOne":3.013,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testTwo":1.001,"PHPUnit\\TestFixture\\ExecutionOrder\\Duration\\FooTest::testThree":2.001}} \ No newline at end of file diff --git a/tests/end-to-end/execution-order/order-by-default-test-classes-with-defects.phpt b/tests/end-to-end/execution-order/order-by-default-test-classes-with-defects.phpt new file mode 100644 index 00000000000..1f279399012 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-classes-with-defects.phpt @@ -0,0 +1,67 @@ +--TEST-- +Default order: Test classes with defects +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (8 tests) +Test Suite Started (CLI Arguments, 8 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Suite Finished (CLI Arguments, 8 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-default-test-classes-with-different-sizes.phpt b/tests/end-to-end/execution-order/order-by-default-test-classes-with-different-sizes.phpt new file mode 100644 index 00000000000..ab6af23d139 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-classes-with-different-sizes.phpt @@ -0,0 +1,45 @@ +--TEST-- +Default order: Suite with test classes that have different sizes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest, 1 test) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-default-test-classes.phpt b/tests/end-to-end/execution-order/order-by-default-test-classes.phpt new file mode 100644 index 00000000000..76a7d37c4bc --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-classes.phpt @@ -0,0 +1,43 @@ +--TEST-- +Default order: Suite with test classes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\BarTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\BarTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-default-test-methods-with-defects.phpt b/tests/end-to-end/execution-order/order-by-default-test-methods-with-defects.phpt new file mode 100644 index 00000000000..31f370c21c9 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-methods-with-defects.phpt @@ -0,0 +1,47 @@ +--TEST-- +Default order: Test methods with defects +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (CLI Arguments, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Suite Finished (CLI Arguments, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-default-test-methods-with-dependencies.phpt b/tests/end-to-end/execution-order/order-by-default-test-methods-with-dependencies.phpt new file mode 100644 index 00000000000..177b5bf3084 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-methods-with-dependencies.phpt @@ -0,0 +1,35 @@ +--TEST-- +Default order: Test methods with dependencies +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-default-test-methods.phpt b/tests/end-to-end/execution-order/order-by-default-test-methods.phpt new file mode 100644 index 00000000000..78df5a33182 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-default-test-methods.phpt @@ -0,0 +1,35 @@ +--TEST-- +Default order: Test methods +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects-but-result-cache-does-not-exist.phpt b/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects-but-result-cache-does-not-exist.phpt new file mode 100644 index 00000000000..62602b89412 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects-but-result-cache-does-not-exist.phpt @@ -0,0 +1,74 @@ +--TEST-- +Order by defects (without result cache): Test classes with defects +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (8 tests) +Test Suite Started (CLI Arguments, 8 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Suite Finished (CLI Arguments, 8 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects.phpt b/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects.phpt new file mode 100644 index 00000000000..1f7c59745d1 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-defects-test-classes-with-defects.phpt @@ -0,0 +1,81 @@ +--TEST-- +Order by defects (with result cache): Test classes with defects +--XFAIL-- +After merging https://github.com/sebastianbergmann/phpunit/pull/6338 into PHPUnit 10.5 and merging it from there to PHPUnit 12.4 via PHPUnit 11.5, this test now fails. +This test failure needs to be investigated. Hopefully, it fails for the obvious reason: that the result cache file needs to be updated. +--FILE-- +run($_SERVER['argv']); + +unlink($testResultsFile); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (8 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (8 tests) +Test Suite Started (CLI Arguments, 8 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testFour) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BarTest, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\BazTest, 4 tests) +Test Suite Finished (CLI Arguments, 8 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects-but-result-cache-does-not-exist.phpt b/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects-but-result-cache-does-not-exist.phpt new file mode 100644 index 00000000000..6e075f7408c --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects-but-result-cache-does-not-exist.phpt @@ -0,0 +1,54 @@ +--TEST-- +Order by defects (without result cache): Test methods with defects +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (CLI Arguments, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Suite Finished (CLI Arguments, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects.phpt b/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects.phpt new file mode 100644 index 00000000000..a41a8ff269e --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-defects-test-methods-with-defects.phpt @@ -0,0 +1,61 @@ +--TEST-- +Order by defects (with result cache): Test methods with defects +--XFAIL-- +After merging https://github.com/sebastianbergmann/phpunit/pull/6338 into PHPUnit 10.5 and merging it from there to PHPUnit 12.4 via PHPUnit 11.5, this test now fails. +This test failure needs to be investigated. Hopefully, it fails for the obvious reason: that the result cache file needs to be updated. +--FILE-- +run($_SERVER['argv']); + +unlink($testResultsFile); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (4 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (4 tests) +Test Suite Started (CLI Arguments, 4 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Errored (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +message +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Failed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest::testFour) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Defects\FooTest, 4 tests) +Test Suite Finished (CLI Arguments, 4 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/execution-order/order-by-duration-test-classes-but-result-cache-does-not-exist.phpt b/tests/end-to-end/execution-order/order-by-duration-test-classes-but-result-cache-does-not-exist.phpt new file mode 100644 index 00000000000..8bf89973029 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-duration-test-classes-but-result-cache-does-not-exist.phpt @@ -0,0 +1,62 @@ +--TEST-- +Order by duration (without result cache) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (6 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (6 tests) +Test Suite Started (CLI Arguments, 6 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Suite Finished (CLI Arguments, 6 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-duration-test-classes.phpt b/tests/end-to-end/execution-order/order-by-duration-test-classes.phpt new file mode 100644 index 00000000000..bed6ebed8ab --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-duration-test-classes.phpt @@ -0,0 +1,66 @@ +--TEST-- +Order by duration (with result cache) +--FILE-- +run($_SERVER['argv']); + +unlink($testResultsFile); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (6 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (6 tests) +Test Suite Started (CLI Arguments, 6 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Suite Finished (CLI Arguments, 6 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-duration-test-methods-but-result-cache-does-not-exist.phpt b/tests/end-to-end/execution-order/order-by-duration-test-methods-but-result-cache-does-not-exist.phpt new file mode 100644 index 00000000000..d949a38ff12 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-duration-test-methods-but-result-cache-does-not-exist.phpt @@ -0,0 +1,48 @@ +--TEST-- +Order by duration (without result cache) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-duration-test-methods.phpt b/tests/end-to-end/execution-order/order-by-duration-test-methods.phpt new file mode 100644 index 00000000000..6bf314b08b0 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-duration-test-methods.phpt @@ -0,0 +1,52 @@ +--TEST-- +Order by duration (with result cache) +--FILE-- +run($_SERVER['argv']); + +unlink($testResultsFile); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-no-depends-test-methods-with-dependencies.phpt b/tests/end-to-end/execution-order/order-by-no-depends-test-methods-with-dependencies.phpt new file mode 100644 index 00000000000..87b7bfbd120 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-no-depends-test-methods-with-dependencies.phpt @@ -0,0 +1,32 @@ +--TEST-- +Default order: Test methods with dependencies +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest, 2 tests) +Test Skipped (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testOne) +This test depends on "PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo" to pass +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Dependencies\FooTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-random-test-classes.phpt b/tests/end-to-end/execution-order/order-by-random-test-classes.phpt new file mode 100644 index 00000000000..b070b8f3acc --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-random-test-classes.phpt @@ -0,0 +1,57 @@ +--TEST-- +Random order: Suite with test classes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (6 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (6 tests) +Test Suite Started (CLI Arguments, 6 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\BarTest, 3 tests) +Test Suite Finished (CLI Arguments, 6 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-random-test-methods.phpt b/tests/end-to-end/execution-order/order-by-random-test-methods.phpt new file mode 100644 index 00000000000..1bd7dafb60c --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-random-test-methods.phpt @@ -0,0 +1,41 @@ +--TEST-- +Random order: Suite with test classes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testThree) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\Duration\FooTest, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-reverse-test-classes.phpt b/tests/end-to-end/execution-order/order-by-reverse-test-classes.phpt new file mode 100644 index 00000000000..591e0ff5c69 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-reverse-test-classes.phpt @@ -0,0 +1,43 @@ +--TEST-- +Reverse order: Suite with test classes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\BarTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\BarTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\BarTest, 1 test) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-reverse-test-methods.phpt b/tests/end-to-end/execution-order/order-by-reverse-test-methods.phpt new file mode 100644 index 00000000000..5a8adb69244 --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-reverse-test-methods.phpt @@ -0,0 +1,35 @@ +--TEST-- +Reverse order: Test methods +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testTwo) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\FooTest, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/execution-order/order-by-size-test-classes-with-different-sizes.phpt b/tests/end-to-end/execution-order/order-by-size-test-classes-with-different-sizes.phpt new file mode 100644 index 00000000000..3cad0dc480b --- /dev/null +++ b/tests/end-to-end/execution-order/order-by-size-test-classes-with-different-sizes.phpt @@ -0,0 +1,47 @@ +--TEST-- +Order by test size: Suite with test classes that have different sizes +--XFAIL-- +TestSuiteSorter::cmpSize() does not handle TestSuite objects for TestCase classes +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\UnitTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\IntegrationTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Passed (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExecutionOrder\DifferentSizes\EndToEndTest, 1 test) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-exist/phpunit.xml b/tests/end-to-end/extension-cli/_files/class-does-not-exist/phpunit.xml new file mode 100644 index 00000000000..c4d7b898f3f --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-exist/phpunit.xml @@ -0,0 +1,9 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-exist/tests/Test.php b/tests/end-to-end/extension-cli/_files/class-does-not-exist/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-exist/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/phpunit.xml b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/phpunit.xml new file mode 100644 index 00000000000..aaa950205d4 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..0fbf797d553 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +final class MyExtensionBootstrap +{ +} diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/autoload.php b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/tests/Test.php b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/class-does-not-implement-interface/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/phpunit.xml b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/phpunit.xml new file mode 100644 index 00000000000..aaa950205d4 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..763a61a70b9 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; +use RuntimeException; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + throw new RuntimeException('message'); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/autoload.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/tests/Test.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-bootstrap-method/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/phpunit.xml b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/phpunit.xml new file mode 100644 index 00000000000..aaa950205d4 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..5967340604c --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; +use RuntimeException; + +final class MyExtensionBootstrap implements Extension +{ + public function __construct() + { + throw new RuntimeException('message'); + } + + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/autoload.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/tests/Test.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-constructor/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/phpunit.xml b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/phpunit.xml new file mode 100644 index 00000000000..aaa950205d4 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..2c4719b88b3 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +use RuntimeException; + +final class MyExecutionFinishedSubscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + throw new RuntimeException('message'); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..9c0174a96cd --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + $facade->registerSubscriber(new MyExecutionFinishedSubscriber); + } +} diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/autoload.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/autoload.php new file mode 100644 index 00000000000..98531b415f5 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; + +require __DIR__ . '/MyExecutionFinishedSubscriber.php'; diff --git a/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/tests/Test.php b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/exception-in-extension-subscriber/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/_files/extension-bootstrap/phpunit.xml b/tests/end-to-end/extension-cli/_files/extension-bootstrap/phpunit.xml new file mode 100644 index 00000000000..aaa950205d4 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/extension-bootstrap/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..7e7be91538d --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use const PHP_EOL; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; + +final class MyExecutionFinishedSubscriber implements ExecutionFinishedSubscriber +{ + private readonly string $message; + + public function __construct(string $message) + { + $this->message = $message; + } + + public function notify(ExecutionFinished $event): void + { + print __METHOD__ . PHP_EOL; + print $this->message . PHP_EOL; + } +} diff --git a/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..a80872588d0 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/MyExtensionBootstrap.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + $facade->registerSubscriber( + new MyExecutionFinishedSubscriber( + 'the-message', + ), + ); + } +} diff --git a/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/autoload.php b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/autoload.php new file mode 100644 index 00000000000..98531b415f5 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/extension-bootstrap/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; + +require __DIR__ . '/MyExecutionFinishedSubscriber.php'; diff --git a/tests/end-to-end/extension-cli/_files/extension-bootstrap/tests/Test.php b/tests/end-to-end/extension-cli/_files/extension-bootstrap/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-cli/_files/extension-bootstrap/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-cli/bootstrap.phpt b/tests/end-to-end/extension-cli/bootstrap.phpt new file mode 100644 index 00000000000..256a9e4fd33 --- /dev/null +++ b/tests/end-to-end/extension-cli/bootstrap.phpt @@ -0,0 +1,17 @@ +--TEST-- +A PHPUnit extension can subscribe to events +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit\TestFixture\Event\MyExtension\MyExecutionFinishedSubscriber::notify +the-message diff --git a/tests/end-to-end/extension-cli/class-does-not-exist.phpt b/tests/end-to-end/extension-cli/class-does-not-exist.phpt new file mode 100644 index 00000000000..e3bc355ad4b --- /dev/null +++ b/tests/end-to-end/extension-cli/class-does-not-exist.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test runner exits with error when configured extension class does not exit +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot bootstrap extension because class Does\Not\Exist does not exist + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-cli/class-does-not-implement-interface.phpt b/tests/end-to-end/extension-cli/class-does-not-implement-interface.phpt new file mode 100644 index 00000000000..62daa811cda --- /dev/null +++ b/tests/end-to-end/extension-cli/class-does-not-implement-interface.phpt @@ -0,0 +1,29 @@ +--TEST-- +Test runner exits with error when configured extension class does not implement the interface +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot bootstrap extension because class PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap does not implement interface PHPUnit\Runner\Extension\Extension + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-cli/exception-in-extension-bootstrap-method.phpt b/tests/end-to-end/extension-cli/exception-in-extension-bootstrap-method.phpt new file mode 100644 index 00000000000..aacfa9fef7c --- /dev/null +++ b/tests/end-to-end/extension-cli/exception-in-extension-bootstrap-method.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's bootstrap method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Bootstrapping of extension PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap failed: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-cli/exception-in-extension-constructor.phpt b/tests/end-to-end/extension-cli/exception-in-extension-constructor.phpt new file mode 100644 index 00000000000..70283661738 --- /dev/null +++ b/tests/end-to-end/extension-cli/exception-in-extension-constructor.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's bootstrap class' constructor +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Bootstrapping of extension PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap failed: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-cli/exception-in-extension-subscriber.phpt b/tests/end-to-end/extension-cli/exception-in-extension-subscriber.phpt new file mode 100644 index 00000000000..ba96c1fe4ae --- /dev/null +++ b/tests/end-to-end/extension-cli/exception-in-extension-subscriber.phpt @@ -0,0 +1,30 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's event subscriber +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Exception in third-party event subscriber: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-exist/phpunit.xml b/tests/end-to-end/extension-xml/_files/class-does-not-exist/phpunit.xml new file mode 100644 index 00000000000..470d632a125 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-exist/phpunit.xml @@ -0,0 +1,13 @@ + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-exist/tests/Test.php b/tests/end-to-end/extension-xml/_files/class-does-not-exist/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-exist/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/phpunit.xml b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/phpunit.xml new file mode 100644 index 00000000000..23bddb8fe44 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/phpunit.xml @@ -0,0 +1,14 @@ + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..0fbf797d553 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/MyExtensionBootstrap.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +final class MyExtensionBootstrap +{ +} diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/autoload.php b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/tests/Test.php b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/class-does-not-implement-interface/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/phpunit.xml b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/phpunit.xml new file mode 100644 index 00000000000..c3ab6c75ae6 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..763a61a70b9 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/MyExtensionBootstrap.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; +use RuntimeException; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + throw new RuntimeException('message'); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/autoload.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/tests/Test.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-bootstrap-method/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit-without-parameter.xml b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit-without-parameter.xml new file mode 100644 index 00000000000..23bddb8fe44 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit-without-parameter.xml @@ -0,0 +1,14 @@ + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit.xml b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit.xml new file mode 100644 index 00000000000..c3ab6c75ae6 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..5967340604c --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/MyExtensionBootstrap.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; +use RuntimeException; + +final class MyExtensionBootstrap implements Extension +{ + public function __construct() + { + throw new RuntimeException('message'); + } + + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/autoload.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/autoload.php new file mode 100644 index 00000000000..c84415b0429 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/tests/Test.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-constructor/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/phpunit.xml b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/phpunit.xml new file mode 100644 index 00000000000..c3ab6c75ae6 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..2c4719b88b3 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExecutionFinishedSubscriber.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +use RuntimeException; + +final class MyExecutionFinishedSubscriber implements ExecutionFinishedSubscriber +{ + public function notify(ExecutionFinished $event): void + { + throw new RuntimeException('message'); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..9c0174a96cd --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/MyExtensionBootstrap.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + $facade->registerSubscriber(new MyExecutionFinishedSubscriber); + } +} diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/autoload.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/autoload.php new file mode 100644 index 00000000000..98531b415f5 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; + +require __DIR__ . '/MyExecutionFinishedSubscriber.php'; diff --git a/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/tests/Test.php b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/exception-in-extension-subscriber/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit-without-parameter.xml b/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit-without-parameter.xml new file mode 100644 index 00000000000..23bddb8fe44 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit-without-parameter.xml @@ -0,0 +1,14 @@ + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit.xml b/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit.xml new file mode 100644 index 00000000000..c3ab6c75ae6 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/phpunit.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + tests + + + diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php new file mode 100644 index 00000000000..7e7be91538d --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExecutionFinishedSubscriber.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use const PHP_EOL; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; + +final class MyExecutionFinishedSubscriber implements ExecutionFinishedSubscriber +{ + private readonly string $message; + + public function __construct(string $message) + { + $this->message = $message; + } + + public function notify(ExecutionFinished $event): void + { + print __METHOD__ . PHP_EOL; + print $this->message . PHP_EOL; + } +} diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExtensionBootstrap.php b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExtensionBootstrap.php new file mode 100644 index 00000000000..aea06b5b6e5 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/MyExtensionBootstrap.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Runner\Extension\Extension; +use PHPUnit\Runner\Extension\Facade; +use PHPUnit\Runner\Extension\ParameterCollection; +use PHPUnit\TextUI\Configuration\Configuration; + +final class MyExtensionBootstrap implements Extension +{ + public function bootstrap(Configuration $configuration, Facade $facade, ParameterCollection $parameters): void + { + $message = 'the-default-message'; + + if ($parameters->has('message')) { + $message = $parameters->get('message'); + } + + $facade->registerSubscriber( + new MyExecutionFinishedSubscriber( + $message, + ), + ); + } +} diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/autoload.php b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/autoload.php new file mode 100644 index 00000000000..98531b415f5 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/src/autoload.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/MyExtensionBootstrap.php'; + +require __DIR__ . '/MyExecutionFinishedSubscriber.php'; diff --git a/tests/end-to-end/extension-xml/_files/extension-bootstrap/tests/Test.php b/tests/end-to-end/extension-xml/_files/extension-bootstrap/tests/Test.php new file mode 100644 index 00000000000..a6c86c85797 --- /dev/null +++ b/tests/end-to-end/extension-xml/_files/extension-bootstrap/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event\MyExtension; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/extension-xml/bootstrap-with-parameter.phpt b/tests/end-to-end/extension-xml/bootstrap-with-parameter.phpt new file mode 100644 index 00000000000..ea6ed325f7a --- /dev/null +++ b/tests/end-to-end/extension-xml/bootstrap-with-parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +A PHPUnit extension can subscribe to events +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit\TestFixture\Event\MyExtension\MyExecutionFinishedSubscriber::notify +the-message diff --git a/tests/end-to-end/extension-xml/bootstrap-without-parameter.phpt b/tests/end-to-end/extension-xml/bootstrap-without-parameter.phpt new file mode 100644 index 00000000000..9e4a18d0ca4 --- /dev/null +++ b/tests/end-to-end/extension-xml/bootstrap-without-parameter.phpt @@ -0,0 +1,15 @@ +--TEST-- +A PHPUnit extension can subscribe to events +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit\TestFixture\Event\MyExtension\MyExecutionFinishedSubscriber::notify +the-default-message diff --git a/tests/end-to-end/extension-xml/class-does-not-exist.phpt b/tests/end-to-end/extension-xml/class-does-not-exist.phpt new file mode 100644 index 00000000000..910e121fcf2 --- /dev/null +++ b/tests/end-to-end/extension-xml/class-does-not-exist.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test runner exits with error when configured extension class does not exit +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot bootstrap extension because class Does\Not\Exist does not exist + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/class-does-not-implement-interface.phpt b/tests/end-to-end/extension-xml/class-does-not-implement-interface.phpt new file mode 100644 index 00000000000..3be29058d55 --- /dev/null +++ b/tests/end-to-end/extension-xml/class-does-not-implement-interface.phpt @@ -0,0 +1,27 @@ +--TEST-- +Test runner exits with error when configured extension class does not implement the interface +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot bootstrap extension because class PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap does not implement interface PHPUnit\Runner\Extension\Extension + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/exception-in-extension-bootstrap-method.phpt b/tests/end-to-end/extension-xml/exception-in-extension-bootstrap-method.phpt new file mode 100644 index 00000000000..672a4256abb --- /dev/null +++ b/tests/end-to-end/extension-xml/exception-in-extension-bootstrap-method.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's bootstrap method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Bootstrapping of extension PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap failed: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/exception-in-extension-constructor.phpt b/tests/end-to-end/extension-xml/exception-in-extension-constructor.phpt new file mode 100644 index 00000000000..168f28b654c --- /dev/null +++ b/tests/end-to-end/extension-xml/exception-in-extension-constructor.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's bootstrap class' constructor +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Bootstrapping of extension PHPUnit\TestFixture\Event\MyExtension\MyExtensionBootstrap failed: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/exception-in-extension-subscriber.phpt b/tests/end-to-end/extension-xml/exception-in-extension-subscriber.phpt new file mode 100644 index 00000000000..99884e60057 --- /dev/null +++ b/tests/end-to-end/extension-xml/exception-in-extension-subscriber.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner warning is triggered when an exception is triggered in an extension's event subscriber +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Exception in third-party event subscriber: message +%A + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/extension-xml/phar-extension.phpt b/tests/end-to-end/extension-xml/phar-extension.phpt new file mode 100644 index 00000000000..55a9405df79 --- /dev/null +++ b/tests/end-to-end/extension-xml/phar-extension.phpt @@ -0,0 +1,35 @@ +--TEST-- +The right events are emitted in the right order when a PHPUnit extension from a PHAR is loaded +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Extension Loaded from PHAR (phpunit/phpunit-test-extension 1.0.0) +Extension Bootstrapped (PHPUnit\TestFixture\MyExtension\MyExtensionBootstrap) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s%etests%eend-to-end%e_files%ephar-extension%ephpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Event\MyExtension\Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Event\MyExtension\Test::testOne) +Test Prepared (PHPUnit\TestFixture\Event\MyExtension\Test::testOne) +Test Passed (PHPUnit\TestFixture\Event\MyExtension\Test::testOne) +Test Finished (PHPUnit\TestFixture\Event\MyExtension\Test::testOne) +Test Suite Finished (PHPUnit\TestFixture\Event\MyExtension\Test, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%s%etests%eend-to-end%e_files%ephar-extension%ephpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/_files/ExpectErrorLogFailTest.php b/tests/end-to-end/generic/_files/ExpectErrorLogFailTest.php new file mode 100644 index 00000000000..e27a6911158 --- /dev/null +++ b/tests/end-to-end/generic/_files/ExpectErrorLogFailTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExpectNoErrorLog; + +use PHPUnit\Framework\TestCase; + +class FooBar +{ + public function doFoo() + { + return ''; + } +} + +final class ExpectErrorLogFailTest extends TestCase +{ + public function testOne(): void + { + $foo = new FooBar; + + $this->assertSame('', $foo->doFoo()); + $this->expectErrorLog(); + } +} diff --git a/tests/end-to-end/generic/_files/ExpectErrorLogTest.php b/tests/end-to-end/generic/_files/ExpectErrorLogTest.php new file mode 100644 index 00000000000..2c374c1fa01 --- /dev/null +++ b/tests/end-to-end/generic/_files/ExpectErrorLogTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\ExpectErrorLog; + +use function error_log; +use PHPUnit\Framework\TestCase; + +class Foo +{ + public function doFoo() + { + error_log('logged a side effect'); + + return ''; + } +} + +final class ExpectErrorLogTest extends TestCase +{ + public function testOne(): void + { + $foo = new Foo; + + $this->assertSame('', $foo->doFoo()); + $this->expectErrorLog(); + } +} diff --git a/tests/end-to-end/generic/_files/TestForDeprecatedFeatureInIsolationTest.php b/tests/end-to-end/generic/_files/TestForDeprecatedFeatureInIsolationTest.php new file mode 100644 index 00000000000..34022e9fe9e --- /dev/null +++ b/tests/end-to-end/generic/_files/TestForDeprecatedFeatureInIsolationTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class TestForDeprecatedFeatureInIsolationTest extends TestCase +{ + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + + @trigger_error('message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationsOnExactDeprecationMessagesWorkWhenExpectedDeprecationsAreTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + $this->expectUserDeprecationMessage('another message'); + + @trigger_error('message', E_USER_DEPRECATED); + @trigger_error('another message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + } + + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + + @trigger_error('another message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + + @trigger_error('...message...', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationsOnDeprecationMessagesMatchingRegularExpressionsWorkWhenExpectedDeprecationsAreTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/foo/'); + $this->expectUserDeprecationMessageMatches('/bar/'); + + @trigger_error('...foo...', E_USER_DEPRECATED); + @trigger_error('...bar...', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + + @trigger_error('something else', E_USER_DEPRECATED); + } +} diff --git a/tests/end-to-end/generic/_files/TestForDeprecatedFeatureTest.php b/tests/end-to-end/generic/_files/TestForDeprecatedFeatureTest.php new file mode 100644 index 00000000000..e322b407fa7 --- /dev/null +++ b/tests/end-to-end/generic/_files/TestForDeprecatedFeatureTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Event; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\TestCase; + +final class TestForDeprecatedFeatureTest extends TestCase +{ + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + + @trigger_error('message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationsOnExactDeprecationMessagesWorkWhenExpectedDeprecationsAreTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + $this->expectUserDeprecationMessage('another message'); + + @trigger_error('message', E_USER_DEPRECATED); + @trigger_error('another message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + } + + #[IgnoreDeprecations] + public function testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessage('message'); + + @trigger_error('another message', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + + @trigger_error('...message...', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationsOnDeprecationMessagesMatchingRegularExpressionsWorkWhenExpectedDeprecationsAreTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/foo/'); + $this->expectUserDeprecationMessageMatches('/bar/'); + + @trigger_error('...foo...', E_USER_DEPRECATED); + @trigger_error('...bar...', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + } + + #[IgnoreDeprecations] + public function testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered(): void + { + $this->expectUserDeprecationMessageMatches('/message/'); + + @trigger_error('something else', E_USER_DEPRECATED); + } +} diff --git a/tests/end-to-end/generic/abstract-test-class/abstract-test-class-with-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/abstract-test-class-with-test-suffix.phpt new file mode 100644 index 00000000000..f9a8a9cfe16 --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/abstract-test-class-with-test-suffix.phpt @@ -0,0 +1,12 @@ +--TEST-- +phpunit ../../../_files/abstract/with-test-suffix/AbstractTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Class PHPUnit\TestFixture\AbstractTest declared in %sAbstractTest.php is abstract diff --git a/tests/end-to-end/generic/abstract-test-class/abstract-test-class-without-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/abstract-test-class-without-test-suffix.phpt new file mode 100644 index 00000000000..691bbd80eda --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/abstract-test-class-without-test-suffix.phpt @@ -0,0 +1,12 @@ +--TEST-- +phpunit ../../../_files/abstract/without-test-suffix/AbstractTestCase.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Class PHPUnit\TestFixture\AbstractTestCase declared in %sAbstractTestCase.php is abstract diff --git a/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-with-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-with-test-suffix.phpt new file mode 100644 index 00000000000..f25b38b31c3 --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-with-test-suffix.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../../_files/abstract/with-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithTestSuffixTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-without-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-without-test-suffix.phpt new file mode 100644 index 00000000000..4e4d5da20fb --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/concrete-test-class-extending-abstract-test-class-without-test-suffix.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../../_files/abstract/without-test-suffix/ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-with-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-with-test-suffix.phpt new file mode 100644 index 00000000000..e461db6b5c6 --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-with-test-suffix.phpt @@ -0,0 +1,25 @@ +--TEST-- +phpunit ../../../_files/abstract/with-test-suffix +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Class PHPUnit\TestFixture\AbstractTest declared in %sAbstractTest.php is abstract + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-without-test-suffix.phpt b/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-without-test-suffix.phpt new file mode 100644 index 00000000000..cf8ec7fa06a --- /dev/null +++ b/tests/end-to-end/generic/abstract-test-class/directory-with-concrete-test-class-and-abstract-test-class-without-test-suffix.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../../_files/abstract/without-test-suffix +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/assertion.phpt b/tests/end-to-end/generic/assertion.phpt new file mode 100644 index 00000000000..bff737be7b3 --- /dev/null +++ b/tests/end-to-end/generic/assertion.phpt @@ -0,0 +1,34 @@ +--TEST-- +phpunit ../../_files/AssertionExampleTest.php +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\AssertionExampleTest::testOne +assert(false) + +%s:%i +%s:%i + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-with-path.phpt b/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-with-path.phpt new file mode 100644 index 00000000000..f5f2acd9c38 --- /dev/null +++ b/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-with-path.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --version +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There was 1 PHPUnit test runner warning: + +1) Class WrongClassNameTest cannot be found in %sWrongClassNameTest.php + +No tests executed! diff --git a/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-without-path.phpt b/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-without-path.phpt new file mode 100644 index 00000000000..6cfa84128f6 --- /dev/null +++ b/tests/end-to-end/generic/class-name-does-not-match-filename-invocation-without-path.phpt @@ -0,0 +1,23 @@ +--TEST-- +phpunit --version +--FILE-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +There was 1 PHPUnit test runner warning: + +1) Class WrongClassNameTest cannot be found in %sWrongClassNameTest.php + +No tests executed! diff --git a/tests/end-to-end/generic/configuration-does-not-exist.phpt b/tests/end-to-end/generic/configuration-does-not-exist.phpt new file mode 100644 index 00000000000..10fd993795a --- /dev/null +++ b/tests/end-to-end/generic/configuration-does-not-exist.phpt @@ -0,0 +1,15 @@ +--TEST-- +phpunit --configuration does-not-exist.xml +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Could not read XML from file "does-not-exist.xml" diff --git a/tests/end-to-end/generic/controlled-garbage-collection.phpt b/tests/end-to-end/generic/controlled-garbage-collection.phpt new file mode 100644 index 00000000000..5e08f9c6401 --- /dev/null +++ b/tests/end-to-end/generic/controlled-garbage-collection.phpt @@ -0,0 +1,43 @@ +--TEST-- +phpunit --configuration=__DIR__.'/../_files/controlled-garbage-collection' +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Runner Disabled Garbage Collection +Test Runner Triggered Garbage Collection +Test Suite Started (%s%ephpunit.xml, 2 tests) +Test Suite Started (default, 2 tests) +Test Suite Started (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testOne) +Test Prepared (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testOne) +Test Passed (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testOne) +Test Finished (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testOne) +Test Runner Triggered Garbage Collection +Test Preparation Started (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testTwo) +Test Prepared (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testTwo) +Test Passed (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testTwo) +Test Finished (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest::testTwo) +Test Runner Triggered Garbage Collection +Test Suite Finished (PHPUnit\TestFixture\GarbageCollection\GarbageCollectionTest, 2 tests) +Test Suite Finished (default, 2 tests) +Test Suite Finished (%s%ephpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Triggered Garbage Collection +Test Runner Enabled Garbage Collection +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/cwd-restore-after-test.phpt b/tests/end-to-end/generic/cwd-restore-after-test.phpt new file mode 100644 index 00000000000..cfd976f2a87 --- /dev/null +++ b/tests/end-to-end/generic/cwd-restore-after-test.phpt @@ -0,0 +1,18 @@ +--TEST-- +phpunit ../../_files/CwdRestoreTest.php +--FILE-- +run($_SERVER['argv']); + +var_dump($cwd === getcwd()); +--EXPECTF-- +bool(true) diff --git a/tests/end-to-end/generic/dataprovider-named-arguments.phpt b/tests/end-to-end/generic/dataprovider-named-arguments.phpt new file mode 100644 index 00000000000..8f14acebce7 --- /dev/null +++ b/tests/end-to-end/generic/dataprovider-named-arguments.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../_files/DataProviderNamedArgumentsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/generic/debug-with-telemetry.phpt b/tests/end-to-end/generic/debug-with-telemetry.phpt new file mode 100644 index 00000000000..58a8ee1d1cb --- /dev/null +++ b/tests/end-to-end/generic/debug-with-telemetry.phpt @@ -0,0 +1,30 @@ +--TEST-- +phpunit --debug --with-telemetry ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Started (PHPUnit %s using %s) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Configured +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Event Facade Sealed +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Loaded (1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Started +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Sorted +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Started (1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Started (PHPUnit\TestFixture\Basic\SuccessTest, 1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Preparation Started (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Prepared (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Passed (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Finished (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Suite Finished (PHPUnit\TestFixture\Basic\SuccessTest, 1 test) +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Execution Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] Test Runner Finished +[%s:%s:%s.%s / %s:%s:%s.%s] [%s bytes] PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/debug.phpt b/tests/end-to-end/generic/debug.phpt new file mode 100644 index 00000000000..d43cd14c4b3 --- /dev/null +++ b/tests/end-to-end/generic/debug.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit --debug ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Basic\SuccessTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +Test Prepared (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +Test Passed (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +Test Finished (PHPUnit\TestFixture\Basic\SuccessTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\Basic\SuccessTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/default-isolation.phpt b/tests/end-to-end/generic/default-isolation.phpt new file mode 100644 index 00000000000..ef1ce89a10f --- /dev/null +++ b/tests/end-to-end/generic/default-isolation.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --process-isolation ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/generic/default.phpt b/tests/end-to-end/generic/default.phpt new file mode 100644 index 00000000000..202968bd678 --- /dev/null +++ b/tests/end-to-end/generic/default.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/generic/defaulttestsuite-using-testsuite-without-name.phpt b/tests/end-to-end/generic/defaulttestsuite-using-testsuite-without-name.phpt new file mode 100644 index 00000000000..e44a3990bcc --- /dev/null +++ b/tests/end-to-end/generic/defaulttestsuite-using-testsuite-without-name.phpt @@ -0,0 +1,17 @@ +--TEST-- +phpunit --configuration=__DIR__.'/../../_files/configuration.testsuite_no_name.xml' +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Cannot load XML configuration file %sconfiguration.testsuite_no_name.xml because it has validation errors: + + Line 3: + - Element 'testsuite': The attribute 'name' is required but missing. diff --git a/tests/end-to-end/generic/defaulttestsuite-using-testsuite.phpt b/tests/end-to-end/generic/defaulttestsuite-using-testsuite.phpt new file mode 100644 index 00000000000..244a6cb36f6 --- /dev/null +++ b/tests/end-to-end/generic/defaulttestsuite-using-testsuite.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit --testdox --configuration=__DIR__.'/../_files/configuration.defaulttestsuite.xml' --testsuite 'First' +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +Time: %s, Memory: %s + +Dummy Foo (PHPUnit\TestFixture\DummyFoo) + ✔ Foo equals foo + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/defaulttestsuite.phpt b/tests/end-to-end/generic/defaulttestsuite.phpt new file mode 100644 index 00000000000..1c59a2f17bf --- /dev/null +++ b/tests/end-to-end/generic/defaulttestsuite.phpt @@ -0,0 +1,24 @@ +--TEST-- +phpunit --testdox --configuration=__DIR__.'/../_files/configuration.defaulttestsuite.xml' +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +Time: %s, Memory: %s + +Dummy Bar (PHPUnit\TestFixture\DummyBar) + ✔ Bar equals bar + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/deprecation-can-be-expected.phpt b/tests/end-to-end/generic/deprecation-can-be-expected.phpt new file mode 100644 index 00000000000..17ea5eda2e1 --- /dev/null +++ b/tests/end-to-end/generic/deprecation-can-be-expected.phpt @@ -0,0 +1,36 @@ +--TEST-- +E_USER_DEPRECATED issues can be expected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..FF..FF 8 / 8 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message "message" was not triggered + +2) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered +Expected deprecation with message "message" was not triggered + +3) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +4) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +FAILURES! +Tests: 8, Assertions: 10, Failures: 4. diff --git a/tests/end-to-end/generic/deprecations-can-be-ignored-using-attribute.phpt b/tests/end-to-end/generic/deprecations-can-be-ignored-using-attribute.phpt new file mode 100644 index 00000000000..cb741279e6e --- /dev/null +++ b/tests/end-to-end/generic/deprecations-can-be-ignored-using-attribute.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5532 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.D.D 4 / 4 (100%) + +Time: %s, Memory: %s + +2 tests triggered 2 deprecations: + +1) %sIgnoreDeprecationsTest.php:%d +message + +2) %sIgnoreDeprecationsTest.php:%d +message + +OK, but there were issues! +Tests: 4, Assertions: 6, Deprecations: 2. diff --git a/tests/end-to-end/generic/empty-testcase.phpt b/tests/end-to-end/generic/empty-testcase.phpt new file mode 100644 index 00000000000..34013f76f15 --- /dev/null +++ b/tests/end-to-end/generic/empty-testcase.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit ../../_files/EmptyTestCaseTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\EmptyTestCaseTest". + +No tests executed! diff --git a/tests/end-to-end/generic/exception-in-mock-destructor.phpt b/tests/end-to-end/generic/exception-in-mock-destructor.phpt new file mode 100644 index 00000000000..3a2e2e4f86f --- /dev/null +++ b/tests/end-to-end/generic/exception-in-mock-destructor.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit ../../_files/ExceptionInMockDestructorTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\ExceptionInMockDestructorTest::testOne +Exception: Some exception. + +%sExceptionInMockDestructor.php:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/generic/exception-stack.phpt b/tests/end-to-end/generic/exception-stack.phpt new file mode 100644 index 00000000000..ea9de2142a5 --- /dev/null +++ b/tests/end-to-end/generic/exception-stack.phpt @@ -0,0 +1,67 @@ +--TEST-- +phpunit ../../_files/ExceptionStackTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +EE 2 / 2 (100%) + +Time: %s, Memory: %s + +There were 2 errors: + +1) PHPUnit\TestFixture\ExceptionStackTest::testPrintingChildException +PHPUnit\Framework\Exception: Child exception +message +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1 ++ 0 => 2 + ) + + +%s:%i + +Caused by +message +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1 ++ 0 => 2 + ) + +%s:%i + +2) PHPUnit\TestFixture\ExceptionStackTest::testNestedExceptions +Exception: One + +%s:%i + +Caused by +InvalidArgumentException: Two + +%s:%i + +Caused by +Exception: Three + +%s:%i + +ERRORS! +Tests: 2, Assertions: 1, Errors: 2. diff --git a/tests/end-to-end/generic/expect-error-log-fail-with-open_basedir.phpt b/tests/end-to-end/generic/expect-error-log-fail-with-open_basedir.phpt new file mode 100644 index 00000000000..a6b92bc66a4 --- /dev/null +++ b/tests/end-to-end/generic/expect-error-log-fail-with-open_basedir.phpt @@ -0,0 +1,42 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6197 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Errored (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Could not create writable file for error_log() +Test Finished (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/generic/expect-error-log-fail.phpt b/tests/end-to-end/generic/expect-error-log-fail.phpt new file mode 100644 index 00000000000..757457699f6 --- /dev/null +++ b/tests/end-to-end/generic/expect-error-log-fail.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/2155 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Failed (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +error_log() was not called +Failed asserting that a string is not empty. +Test Finished (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExpectNoErrorLog\ExpectErrorLogFailTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/generic/expect-error-log-with-open_basedir.phpt b/tests/end-to-end/generic/expect-error-log-with-open_basedir.phpt new file mode 100644 index 00000000000..3c71500a56c --- /dev/null +++ b/tests/end-to-end/generic/expect-error-log-with-open_basedir.phpt @@ -0,0 +1,33 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6197 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +logged a side effect +Test Errored (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Could not create writable file for error_log() +Test Finished (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/generic/expect-error-log.phpt b/tests/end-to-end/generic/expect-error-log.phpt new file mode 100644 index 00000000000..d2171768932 --- /dev/null +++ b/tests/end-to-end/generic/expect-error-log.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/2155 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Prepared (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Passed (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Finished (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\ExpectErrorLog\ExpectErrorLogTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/expecting-exceptions.phpt b/tests/end-to-end/generic/expecting-exceptions.phpt new file mode 100644 index 00000000000..e438c1a7886 --- /dev/null +++ b/tests/end-to-end/generic/expecting-exceptions.phpt @@ -0,0 +1,59 @@ +--TEST-- +phpunit ../_files/ExpectingExceptionsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.F..FFF..FFF..FFF.FF 20 / 20 (100%) + +Time: %s, Memory: %s + +There were 12 failures: + +1) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectException_and_expected_exception_is_not_thrown +Failed asserting that exception of type "Exception" is thrown. + +2) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectException_and_expectExceptionMessage_and_expected_exception_is_thrown_but_does_not_have_expected_message +Failed asserting that exception message '' contains 'message'. + +3) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionMessage_and_exception_is_thrown_but_does_not_have_expected_message +Failed asserting that exception message '' contains 'message'. + +4) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionMessage_and_no_exception_is_thrown +Failed asserting that exception with message "message" is thrown + +5) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectException_and_expectExceptionMessageMatches_and_expected_exception_is_thrown_but_does_not_have_expected_message +Failed asserting that exception message '' matches '/message/'. + +6) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionMessageMatches_and_exception_is_thrown_but_does_not_have_expected_message +Failed asserting that exception message '' matches '/message/'. + +7) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionMessageMatches_and_no_exception_is_thrown +Failed asserting that exception with message matching "/message/" is thrown + +8) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectException_and_expectExceptionCode_and_expected_exception_is_thrown_but_does_not_have_expected_code +Failed asserting that 0 is equal to expected exception code 1234. + +9) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionCode_and_exception_is_thrown_but_does_not_have_expected_code +Failed asserting that 0 is equal to expected exception code 1234. + +10) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionCode_and_no_exception_is_thrown +Failed asserting that exception with code "1234" is thrown + +11) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionObject_and_expected_exception_is_not_thrown +Failed asserting that 5678 is equal to expected exception code 1234. + +12) PHPUnit\TestFixture\ExpectingExceptionsTest::test_expectExceptionObject_and_no_exception_is_thrown +Failed asserting that exception of type "Exception" is thrown. + +FAILURES! +Tests: 20, Assertions: 30, Failures: 12. diff --git a/tests/end-to-end/generic/failure-isolation.phpt b/tests/end-to-end/generic/failure-isolation.phpt new file mode 100644 index 00000000000..6461d69cb5f --- /dev/null +++ b/tests/end-to-end/generic/failure-isolation.phpt @@ -0,0 +1,142 @@ +--TEST-- +phpunit --process-isolation ../../_files/FailureTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +FFFFFFFFFFFFF 13 / 13 (100%) + +Time: %s, Memory: %s + +There were 13 failures: + +1) PHPUnit\TestFixture\FailureTest::testAssertArrayEqualsArray +message +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1 ++ 0 => 2 + ) + +%s:%i + +2) PHPUnit\TestFixture\FailureTest::testAssertIntegerEqualsInteger +message +Failed asserting that 2 matches expected 1. + +%s:%i + +3) PHPUnit\TestFixture\FailureTest::testAssertObjectEqualsObject +message +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 'foo' => 'bar' ++ 'bar' => 'foo' + ) + +%s:%i + +4) PHPUnit\TestFixture\FailureTest::testAssertNullEqualsString +message +Failed asserting that 'bar' matches expected null. + +%s:%i + +5) PHPUnit\TestFixture\FailureTest::testAssertStringEqualsString +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%i + +6) PHPUnit\TestFixture\FailureTest::testAssertTextEqualsText +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ + 'foo\n +-bar\n ++baz\n + ' + +%s:%i + +7) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormat +message +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-*%s* ++** + +%s:%i + +8) PHPUnit\TestFixture\FailureTest::testAssertNumericEqualsNumeric +message +Failed asserting that 2 matches expected 1. + +%s:%i + +9) PHPUnit\TestFixture\FailureTest::testAssertTextSameText +message +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%i + +10) PHPUnit\TestFixture\FailureTest::testAssertObjectSameObject +message +Failed asserting that two variables reference the same object. + +%s:%i + +11) PHPUnit\TestFixture\FailureTest::testAssertObjectSameNull +message +Failed asserting that null is identical to an object of class "stdClass". + +%s:%i + +12) PHPUnit\TestFixture\FailureTest::testAssertFloatSameFloat +message +Failed asserting that 1.5 is identical to 1.0. + +%s:%i + +13) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormatFile +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-FOO ++...BAR... + +%s:%i + +FAILURES! +Tests: 13, Assertions: 15, Failures: 13. diff --git a/tests/end-to-end/generic/failure.phpt b/tests/end-to-end/generic/failure.phpt new file mode 100644 index 00000000000..2c46c7fb45b --- /dev/null +++ b/tests/end-to-end/generic/failure.phpt @@ -0,0 +1,141 @@ +--TEST-- +phpunit ../../_files/FailureTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +FFFFFFFFFFFFF 13 / 13 (100%) + +Time: %s, Memory: %s + +There were 13 failures: + +1) PHPUnit\TestFixture\FailureTest::testAssertArrayEqualsArray +message +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1 ++ 0 => 2 + ) + +%s:%i + +2) PHPUnit\TestFixture\FailureTest::testAssertIntegerEqualsInteger +message +Failed asserting that 2 matches expected 1. + +%s:%i + +3) PHPUnit\TestFixture\FailureTest::testAssertObjectEqualsObject +message +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 'foo' => 'bar' ++ 'bar' => 'foo' + ) + +%s:%i + +4) PHPUnit\TestFixture\FailureTest::testAssertNullEqualsString +message +Failed asserting that 'bar' matches expected null. + +%s:%i + +5) PHPUnit\TestFixture\FailureTest::testAssertStringEqualsString +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%i + +6) PHPUnit\TestFixture\FailureTest::testAssertTextEqualsText +message +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ + 'foo\n +-bar\n ++baz\n + ' + +%s:%i + +7) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormat +message +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-*%s* ++** + +%s:%i + +8) PHPUnit\TestFixture\FailureTest::testAssertNumericEqualsNumeric +message +Failed asserting that 2 matches expected 1. + +%s:%i + +9) PHPUnit\TestFixture\FailureTest::testAssertTextSameText +message +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +%s:%i + +10) PHPUnit\TestFixture\FailureTest::testAssertObjectSameObject +message +Failed asserting that two variables reference the same object. + +%s:%i + +11) PHPUnit\TestFixture\FailureTest::testAssertObjectSameNull +message +Failed asserting that null is identical to an object of class "stdClass". + +%s:%i + +12) PHPUnit\TestFixture\FailureTest::testAssertFloatSameFloat +message +Failed asserting that 1.5 is identical to 1.0. + +%s:%i + +13) PHPUnit\TestFixture\FailureTest::testAssertStringMatchesFormatFile +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ +-FOO ++...BAR... + +%s:%i + +FAILURES! +Tests: 13, Assertions: 15, Failures: 13. diff --git a/tests/end-to-end/generic/force-covers-annotation.phpt b/tests/end-to-end/generic/force-covers-annotation.phpt new file mode 100644 index 00000000000..7ea1bc88985 --- /dev/null +++ b/tests/end-to-end/generic/force-covers-annotation.phpt @@ -0,0 +1,30 @@ +--TEST-- +phpunit ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\Test::testOne +This test does not define a code coverage target but is expected to do so + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/end-to-end/generic/getActualOutputForAssertion.phpt b/tests/end-to-end/generic/getActualOutputForAssertion.phpt new file mode 100644 index 00000000000..d04aac8206e --- /dev/null +++ b/tests/end-to-end/generic/getActualOutputForAssertion.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../../_files/ActualOutputTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/ini-isolation.phpt b/tests/end-to-end/generic/ini-isolation.phpt new file mode 100644 index 00000000000..74879843e1d --- /dev/null +++ b/tests/end-to-end/generic/ini-isolation.phpt @@ -0,0 +1,23 @@ +--TEST-- +phpunit --process-isolation -d default_mimetype=application/x-test ../../_files/IniTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/invokable-constraint-and-pipe-operator.phpt b/tests/end-to-end/generic/invokable-constraint-and-pipe-operator.phpt new file mode 100644 index 00000000000..46a0ad4ce4e --- /dev/null +++ b/tests/end-to-end/generic/invokable-constraint-and-pipe-operator.phpt @@ -0,0 +1,34 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6354 +--SKIPIF-- +')) { + print 'skip: PHP 8.5 is required.'; +} +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest::testOne) +Test Prepared (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest::testOne) +Test Passed (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest::testOne) +Test Finished (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\InvokableConstraintAndPipeOperatorTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/generic/multiple-arguments.phpt b/tests/end-to-end/generic/multiple-arguments.phpt new file mode 100644 index 00000000000..0b7865d34c0 --- /dev/null +++ b/tests/end-to-end/generic/multiple-arguments.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../../_files/DummyFooTest.php ../../_files/DummyBarTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/generic/no-output.phpt b/tests/end-to-end/generic/no-output.phpt new file mode 100644 index 00000000000..5267c89a6ac --- /dev/null +++ b/tests/end-to-end/generic/no-output.phpt @@ -0,0 +1,12 @@ +--TEST-- +phpunit --no-output ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- diff --git a/tests/end-to-end/generic/no-progress.phpt b/tests/end-to-end/generic/no-progress.phpt new file mode 100644 index 00000000000..0071d1acbe5 --- /dev/null +++ b/tests/end-to-end/generic/no-progress.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --no-progress ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/generic/no-results.phpt b/tests/end-to-end/generic/no-results.phpt new file mode 100644 index 00000000000..05759048bee --- /dev/null +++ b/tests/end-to-end/generic/no-results.phpt @@ -0,0 +1,19 @@ +--TEST-- +phpunit --no-results ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s diff --git a/tests/end-to-end/generic/one-class-per-file-valid.phpt b/tests/end-to-end/generic/one-class-per-file-valid.phpt new file mode 100644 index 00000000000..af56e35a1a8 --- /dev/null +++ b/tests/end-to-end/generic/one-class-per-file-valid.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --version +--FILE-- +run($_SERVER['argv']); +?> +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/outcome-and-issues-individual-options.phpt b/tests/end-to-end/generic/outcome-and-issues-individual-options.phpt new file mode 100644 index 00000000000..968644811f4 --- /dev/null +++ b/tests/end-to-end/generic/outcome-and-issues-individual-options.phpt @@ -0,0 +1,161 @@ +--TEST-- +phpunit --display-incomplete --display-skipped --display-deprecations --display-errors --display-notices --display-warnings ../_files/OutcomesAndIssuesTest +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.RDNWFFFEEEDNWDNW 17 / 17 (100%) + +Time: %s, Memory: %s + +There were 3 errors: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithDeprecation +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithNotice +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithWarning +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 failures: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithDeprecation +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithNotice +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithWarning +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +-- + +There was 1 risky test: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSuccessWithRisky +This test did not perform any assertions + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 incomplete tests: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithDeprecation +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithNotice +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithWarning +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 skipped tests: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithDeprecation +skipped message + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithNotice +skipped message + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithWarning +skipped message + +-- + +5 tests triggered 5 warnings: + +1) %sOutcomesAndIssuesTest.php:%d +warning message + +2) %sOutcomesAndIssuesTest.php:%d +warning message + +3) %sOutcomesAndIssuesTest.php:%d +warning message + +4) %sOutcomesAndIssuesTest.php:%d +warning message + +5) %sOutcomesAndIssuesTest.php:%d +warning message + +-- + +5 tests triggered 5 notices: + +1) %sOutcomesAndIssuesTest.php:%d +notice message + +2) %sOutcomesAndIssuesTest.php:%d +notice message + +3) %sOutcomesAndIssuesTest.php:%d +notice message + +4) %sOutcomesAndIssuesTest.php:%d +notice message + +5) %sOutcomesAndIssuesTest.php:%d +notice message + +-- + +5 tests triggered 5 deprecations: + +1) %sOutcomesAndIssuesTest.php:%d +deprecation message + +2) %sOutcomesAndIssuesTest.php:%d +deprecation message + +3) %sOutcomesAndIssuesTest.php:%d +deprecation message + +4) %sOutcomesAndIssuesTest.php:%d +deprecation message + +5) %sOutcomesAndIssuesTest.php:%d +deprecation message + +ERRORS! +Tests: 17, Assertions: 7, Errors: 3, Failures: 3, Warnings: 5, Deprecations: 5, Notices: 5, Skipped: 3, Incomplete: 3, Risky: 1. diff --git a/tests/end-to-end/generic/outcome-and-issues.phpt b/tests/end-to-end/generic/outcome-and-issues.phpt new file mode 100644 index 00000000000..a3e35b42722 --- /dev/null +++ b/tests/end-to-end/generic/outcome-and-issues.phpt @@ -0,0 +1,156 @@ +--TEST-- +phpunit --display-all-issues ../_files/OutcomesAndIssuesTest +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.RDNWFFFEEEDNWDNW 17 / 17 (100%) + +Time: %s, Memory: %s + +There were 3 errors: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithDeprecation +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithNotice +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testErrorWithWarning +Exception: exception message + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 failures: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithDeprecation +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithNotice +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testFailWithWarning +Failed asserting that false is true. + +%sOutcomesAndIssuesTest.php:%d + +-- + +There was 1 risky test: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSuccessWithRisky +This test did not perform any assertions + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 incomplete tests: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithDeprecation +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithNotice +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testIncompleteWithWarning +incomplete message + +%sOutcomesAndIssuesTest.php:%d + +-- + +There were 3 skipped tests: + +1) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithDeprecation +skipped message + +2) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithNotice +skipped message + +3) PHPUnit\TestFixture\OutcomesAndIssuesTest::testSkippedWithWarning +skipped message + +-- + +5 tests triggered 5 warnings: + +1) %sOutcomesAndIssuesTest.php:%d +warning message + +2) %sOutcomesAndIssuesTest.php:%d +warning message + +3) %sOutcomesAndIssuesTest.php:%d +warning message + +4) %sOutcomesAndIssuesTest.php:%d +warning message + +5) %sOutcomesAndIssuesTest.php:%d +warning message + +-- + +5 tests triggered 5 notices: + +1) %sOutcomesAndIssuesTest.php:%d +notice message + +2) %sOutcomesAndIssuesTest.php:%d +notice message + +3) %sOutcomesAndIssuesTest.php:%d +notice message + +4) %sOutcomesAndIssuesTest.php:%d +notice message + +5) %sOutcomesAndIssuesTest.php:%d +notice message + +-- + +5 tests triggered 5 deprecations: + +1) %sOutcomesAndIssuesTest.php:%d +deprecation message + +2) %sOutcomesAndIssuesTest.php:%d +deprecation message + +3) %sOutcomesAndIssuesTest.php:%d +deprecation message + +4) %sOutcomesAndIssuesTest.php:%d +deprecation message + +5) %sOutcomesAndIssuesTest.php:%d +deprecation message + +ERRORS! +Tests: 17, Assertions: 7, Errors: 3, Failures: 3, Warnings: 5, Deprecations: 5, Notices: 5, Skipped: 3, Incomplete: 3, Risky: 1. diff --git a/tests/end-to-end/generic/output-isolation.phpt b/tests/end-to-end/generic/output-isolation.phpt new file mode 100644 index 00000000000..cc878f86fad --- /dev/null +++ b/tests/end-to-end/generic/output-isolation.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --process-isolation ../../_files/OutputTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.F.F 4 / 4 (100%) + +Time: %s, Memory: %s + +There were 2 failures: + +1) PHPUnit\TestFixture\OutputTest::testExpectOutputStringFooActualBar +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +2) PHPUnit\TestFixture\OutputTest::testExpectOutputRegexFooActualBar +Failed asserting that 'bar' matches PCRE pattern "/foo/". + +FAILURES! +Tests: 4, Assertions: 4, Failures: 2. diff --git a/tests/end-to-end/generic/output.phpt b/tests/end-to-end/generic/output.phpt new file mode 100644 index 00000000000..d00ed6e6711 --- /dev/null +++ b/tests/end-to-end/generic/output.phpt @@ -0,0 +1,35 @@ +--TEST-- +phpunit ../../_files/OutputTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.F.F 4 / 4 (100%) + +Time: %s, Memory: %s + +There were 2 failures: + +1) PHPUnit\TestFixture\OutputTest::testExpectOutputStringFooActualBar +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +2) PHPUnit\TestFixture\OutputTest::testExpectOutputRegexFooActualBar +Failed asserting that 'bar' matches PCRE pattern "/foo/". + +FAILURES! +Tests: 4, Assertions: 4, Failures: 2. diff --git a/tests/end-to-end/generic/phar-extension-suppressed.phpt b/tests/end-to-end/generic/phar-extension-suppressed.phpt new file mode 100644 index 00000000000..eb1c8ebf758 --- /dev/null +++ b/tests/end-to-end/generic/phar-extension-suppressed.phpt @@ -0,0 +1,27 @@ +--TEST-- +phpunit --configuration tests/_files/phar-extension-bootstrap/phpunit.xml --no-extensions +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/report-tests-performing-assertions-when-annotated-with-does-not-perform-assertions.phpt b/tests/end-to-end/generic/report-tests-performing-assertions-when-annotated-with-does-not-perform-assertions.phpt new file mode 100644 index 00000000000..ecb204a446b --- /dev/null +++ b/tests/end-to-end/generic/report-tests-performing-assertions-when-annotated-with-does-not-perform-assertions.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit ../_files/DoesNotPerformAssertionsButPerformingAssertionsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\DoesNotPerformAssertionsButPerformingAssertionsTest::testFalseAndTrueAreStillFine +This test is not expected to perform assertions but performed 2 assertions + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 2, Risky: 1. diff --git a/tests/end-to-end/generic/report-useless-tests-incomplete.phpt b/tests/end-to-end/generic/report-useless-tests-incomplete.phpt new file mode 100644 index 00000000000..f2719d5db47 --- /dev/null +++ b/tests/end-to-end/generic/report-useless-tests-incomplete.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../../_files/IncompleteTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +I 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 1, Assertions: 0, Incomplete: 1. diff --git a/tests/end-to-end/generic/report-useless-tests-isolation.phpt b/tests/end-to-end/generic/report-useless-tests-isolation.phpt new file mode 100644 index 00000000000..cb588744a75 --- /dev/null +++ b/tests/end-to-end/generic/report-useless-tests-isolation.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit --process-isolation ../../_files/IncompleteTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\NothingTest::testNothing +This test did not perform any assertions + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 0, Risky: 1. diff --git a/tests/end-to-end/generic/report-useless-tests.phpt b/tests/end-to-end/generic/report-useless-tests.phpt new file mode 100644 index 00000000000..633c9bb51d7 --- /dev/null +++ b/tests/end-to-end/generic/report-useless-tests.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit ../../_files/NothingTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\NothingTest::testNothing +This test did not perform any assertions + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 0, Risky: 1. diff --git a/tests/end-to-end/generic/separate-processes-test.phpt b/tests/end-to-end/generic/separate-processes-test.phpt new file mode 100644 index 00000000000..60c12a31238 --- /dev/null +++ b/tests/end-to-end/generic/separate-processes-test.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit --no-configuration ../../_files/SeparateProcessesTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +EE 2 / 2 (100%) + +Time: %s, Memory: %s + +There were 2 errors: + +1) PHPUnit\TestFixture\SeparateProcessesTest::testFoo +Test was run in child process and ended unexpectedly + +2) PHPUnit\TestFixture\SeparateProcessesTest::testBar +Test was run in child process and ended unexpectedly + +ERRORS! +Tests: 2, Assertions: 0, Errors: 2. diff --git a/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-1.phpt b/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-1.phpt new file mode 100644 index 00000000000..c181f974542 --- /dev/null +++ b/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-1.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../../_files/ConcreteTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-2.phpt b/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-2.phpt new file mode 100644 index 00000000000..c068c550957 --- /dev/null +++ b/tests/end-to-end/generic/standardtestsuiteloader-issue-4192-2.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../../_files/ConcreteTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/generic/test-suffix-multiple.phpt b/tests/end-to-end/generic/test-suffix-multiple.phpt new file mode 100644 index 00000000000..d4b7b552463 --- /dev/null +++ b/tests/end-to-end/generic/test-suffix-multiple.phpt @@ -0,0 +1,24 @@ +--TEST-- +phpunit --test-suffix .test.php,.my.php ../../_files/ +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +OK (5 tests, 5 assertions) diff --git a/tests/end-to-end/generic/test-suffix-single.phpt b/tests/end-to-end/generic/test-suffix-single.phpt new file mode 100644 index 00000000000..8ca33638a2b --- /dev/null +++ b/tests/end-to-end/generic/test-suffix-single.phpt @@ -0,0 +1,22 @@ +--TEST-- +phpunit --test-suffix .test.php ../../_files/ +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/generic/transform-exception-hook-method.phpt b/tests/end-to-end/generic/transform-exception-hook-method.phpt new file mode 100644 index 00000000000..f6a0fdcc9d3 --- /dev/null +++ b/tests/end-to-end/generic/transform-exception-hook-method.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5300 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\TransformExceptionHookMethod\Test::testOne +PHPUnit\TestFixture\TransformExceptionHookMethod\TransformedException: transformed message + +%s%eTest.php:24 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/generic/unexpected-output-with-progress-printing.phpt b/tests/end-to-end/generic/unexpected-output-with-progress-printing.phpt new file mode 100644 index 00000000000..b18c34a5ae1 --- /dev/null +++ b/tests/end-to-end/generic/unexpected-output-with-progress-printing.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit ../../_files/UnexpectedOutputTest.php +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +array(1) { + ["foo"]=> + string(3) "bar" +} +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/generic/unexpected-output-without-progress-printing.phpt b/tests/end-to-end/generic/unexpected-output-without-progress-printing.phpt new file mode 100644 index 00000000000..ee3449b079f --- /dev/null +++ b/tests/end-to-end/generic/unexpected-output-without-progress-printing.phpt @@ -0,0 +1,27 @@ +--TEST-- +phpunit ../../_files/UnexpectedOutputTest.php +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +array(1) { + ["foo"]=> + string(3) "bar" +} +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/groups-from-configuration/_files/phpunit.xml b/tests/end-to-end/groups-from-configuration/_files/phpunit.xml new file mode 100644 index 00000000000..d81cefb41fb --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/_files/phpunit.xml @@ -0,0 +1,12 @@ + + + + + tests/foo + tests/bar-baz + tests/AnotherTest.php + + + diff --git a/tests/end-to-end/groups-from-configuration/_files/tests/AnotherTest.php b/tests/end-to-end/groups-from-configuration/_files/tests/AnotherTest.php new file mode 100644 index 00000000000..53430c9eefd --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/_files/tests/AnotherTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\GroupsFromConfiguration; + +use PHPUnit\Framework\TestCase; + +final class AnotherTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/groups-from-configuration/_files/tests/bar-baz/BarBazTest.php b/tests/end-to-end/groups-from-configuration/_files/tests/bar-baz/BarBazTest.php new file mode 100644 index 00000000000..fa3412dc9d5 --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/_files/tests/bar-baz/BarBazTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\GroupsFromConfiguration; + +use PHPUnit\Framework\TestCase; + +final class BarBazTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/groups-from-configuration/_files/tests/foo/FooTest.php b/tests/end-to-end/groups-from-configuration/_files/tests/foo/FooTest.php new file mode 100644 index 00000000000..a5019fd098a --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/_files/tests/foo/FooTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\GroupsFromConfiguration; + +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/groups-from-configuration/group-another-group.phpt b/tests/end-to-end/groups-from-configuration/group-another-group.phpt new file mode 100644 index 00000000000..02b04573196 --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/group-another-group.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --configuration _files/phpunit.xml --list-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest::testOne) +Test Prepared (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest::testOne) +Test Passed (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest::testOne) +Test Finished (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\GroupsFromConfiguration\AnotherTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/groups-from-configuration/group-bar.phpt b/tests/end-to-end/groups-from-configuration/group-bar.phpt new file mode 100644 index 00000000000..8d241423263 --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/group-bar.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --configuration _files/phpunit.xml --list-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Prepared (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Passed (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Finished (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/groups-from-configuration/group-baz.phpt b/tests/end-to-end/groups-from-configuration/group-baz.phpt new file mode 100644 index 00000000000..a407cec537a --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/group-baz.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --configuration _files/phpunit.xml --list-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Prepared (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Passed (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Finished (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\GroupsFromConfiguration\BarBazTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/groups-from-configuration/group-foo.phpt b/tests/end-to-end/groups-from-configuration/group-foo.phpt new file mode 100644 index 00000000000..38e19a13bc2 --- /dev/null +++ b/tests/end-to-end/groups-from-configuration/group-foo.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit --configuration _files/phpunit.xml --list-groups +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Suite Filtered (1 test) +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest::testOne) +Test Prepared (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest::testOne) +Test Passed (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest::testOne) +Test Finished (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\GroupsFromConfiguration\FooTest, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/logging/_files/CaseWithDollarSignTest.php b/tests/end-to-end/logging/_files/CaseWithDollarSignTest.php new file mode 100644 index 00000000000..725ad4f2f32 --- /dev/null +++ b/tests/end-to-end/logging/_files/CaseWithDollarSignTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +final class CaseWithDollarSignTest extends TestCase +{ + public static function dataProvider(): iterable + { + yield ['$12.34']; + + yield ['Some text before the price $5.67']; + + yield ['Dollar sign followed by letter $Q']; + + yield ['Alone $ surrounded by spaces']; + } + + #[DataProvider('dataProvider')] + #[TestDox('The "$x" is used for this test')] + public function testSomething(string $x): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/logging/_files/DataProviderTest.php b/tests/end-to-end/logging/_files/DataProviderTest.php new file mode 100644 index 00000000000..4095ae2090a --- /dev/null +++ b/tests/end-to-end/logging/_files/DataProviderTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TeamCity; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderTest extends TestCase +{ + public static function provider(): array + { + return [ + [true], + [false], + ]; + } + + #[DataProvider('provider')] + public function testOne(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/logging/_files/TestDoxGroupTest.php b/tests/end-to-end/logging/_files/TestDoxGroupTest.php new file mode 100644 index 00000000000..e2b64b799c5 --- /dev/null +++ b/tests/end-to-end/logging/_files/TestDoxGroupTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class TestDoxGroupTest extends TestCase +{ + /** + * @group one + */ + public function testOne(): void + { + $this->assertTrue(true); + } + + /** + * @group two + */ + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/logging/_files/ThrowsWithPreviousExceptionTest.php b/tests/end-to-end/logging/_files/ThrowsWithPreviousExceptionTest.php new file mode 100644 index 00000000000..ccff1ed2a19 --- /dev/null +++ b/tests/end-to-end/logging/_files/ThrowsWithPreviousExceptionTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +class ThrowsWithPreviousExceptionTest extends TestCase +{ + public function testFoo(): void + { + throw new Exception( + 'Outer', + previous: new Exception('Inner'), + ); + } +} diff --git a/tests/end-to-end/logging/_files/TypeErrorTest.php b/tests/end-to-end/logging/_files/TypeErrorTest.php new file mode 100644 index 00000000000..dfc908c18b6 --- /dev/null +++ b/tests/end-to-end/logging/_files/TypeErrorTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use DateTime; +use DateTimeImmutable; +use PHPUnit\Framework\TestCase; + +final class TypeErrorTest extends TestCase +{ + private DateTimeImmutable $dateTime; + + protected function setUp(): void + { + $this->dateTime = new DateTime; + } + + public function testMe(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/logging/_files/raw_output_ColorTest.txt b/tests/end-to-end/logging/_files/raw_output_ColorTest.txt new file mode 100644 index 00000000000..193f2eab6e6 --- /dev/null +++ b/tests/end-to-end/logging/_files/raw_output_ColorTest.txt @@ -0,0 +1,30 @@ +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Basic ANSI color highlighting support + ✔ Colorize with no·color  %f ms + ✔ Colorize with one·color  %f ms + ✔ Colorize with multiple·colors  %f ms + ✔ Colorize with invalid·color  %f ms + ✔ Colorize with valid·and·invalid·colors  %f ms + ✔ Colorize path %ephp%eunit%etest.phpt after NULL  %f ms + ✔ Colorize path %ephp%eunit%etest.phpt after empty  %f ms + ✔ Colorize path %ephp%eunit%etest.phpt after %e  %f ms + ✔ Colorize path %ephp%eunit%etest.phpt after %ephp%e  %f ms + ✔ Colorize path %e_d-i.r%et-e_s.t.phpt after empty  %f ms + ✔ dim($m) and colorize('dim',$m) return different ANSI codes  %f ms + ✔ Visualize all whitespace characters in no-spaces  %f ms + ✔ Visualize all whitespace characters in ·space···invaders·  %f ms + ✔ Visualize all whitespace characters in ⇥indent,·space·and·\n↵\r⟵  %f ms + ✔ Visualize whitespace but ignore EOL  %f ms + ✔ Prettify unnamed dataprovider with data set 0  %f ms + ✔ Prettify unnamed dataprovider with data set 1  %f ms + ✔ Prettify named dataprovider with one  %f ms + ✔ Prettify named dataprovider with two  %f ms + ✔ TestDox shows name of data set one with value 1  %f ms + ✔ TestDox shows name of data set two with value 2  %f ms + +OK (21 tests, 21 assertions) diff --git a/tests/end-to-end/logging/_files/raw_output_StatusTest.txt b/tests/end-to-end/logging/_files/raw_output_StatusTest.txt new file mode 100644 index 00000000000..407586f92ad --- /dev/null +++ b/tests/end-to-end/logging/_files/raw_output_StatusTest.txt @@ -0,0 +1,127 @@ +PHPUnit %s Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %sconfiguration.basic.xml + +Time: %s, Memory: %s + +Set Up Before Class (PHPUnit\TestFixture\Basic\SetUpBeforeClass) + ✘ One  %f ms + ┐ + ├ Exception: forcing an Exception in setUpBeforeClass() + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eSetUpBeforeClassTest.php:32 + ┴ + + ↩ Two  %f ms + ┐ + ├ This test was skipped due to an error in a hook method + ┴ + +Set Up (PHPUnit\TestFixture\Basic\SetUp) + ✘ One with set up exception  %f ms + ┐ + ├ RuntimeException: throw exception in setUp + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eSetUpTest.php:30 + ┴ + + ✘ Two with set up exception  %f ms + ┐ + ├ RuntimeException: throw exception in setUp + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eSetUpTest.php:30 + ┴ + +Test result status with and without message + ✔ Success  %f ms + ✘ Failure  %f ms + ┐ + ├ Failed asserting that false is true. + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ✘ Error  %f ms + ┐ + ├ RuntimeException: + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ∅ Incomplete  %f ms + ┐ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ↩ Skipped  %f ms + ┐ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ☢ Risky  %f ms + ┐ + ├ This test did not perform any assertions%w + ┴ + + ⚠ Warning  %f ms + ┐ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ✔ Success with message  %f ms + ✘ Failure with message  %f ms + ┐ + ├ failure with custom message%w + ├ Failed asserting that false is true. + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ✘ Error with message  %f ms + ┐ + ├ RuntimeException: error with custom message + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ∅ Incomplete with message  %f ms + ┐ + ├ incomplete with custom message + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ↩ Skipped with message  %f ms + ┐ + ├ skipped with custom message + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + + ☢ Risky with message  %f ms + ┐ + ├ This test did not perform any assertions%w + ┴ + + ⚠ Warning with message  %f ms + ┐ + ├ warning with custom message + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d + ┴ + +Tear Down After Class (PHPUnit\TestFixture\Basic\TearDownAfterClass) + ✔ One  %f ms + ✔ Two  %f ms + ✘ Tear down after class  0 ms + ┐ + ├ Exception in PHPUnit\TestFixture\Basic\TearDownAfterClassTest::tearDownAfterClass + ├ forcing an Exception in tearDownAfterClass()  + │ + ╵ %stests%eend-to-end%e_files%ebasic%eunit%eTearDownAfterClassTest.php:%d + ┴ + + +ERRORS! +Tests: 21, Assertions: 7, Errors: 5, Failures: 3, Warnings: 2, Skipped: 3, Incomplete: 2, Risky: 2. diff --git a/tests/end-to-end/logging/_files/status/phpunit.xml b/tests/end-to-end/logging/_files/status/phpunit.xml new file mode 100644 index 00000000000..f53f30cfd91 --- /dev/null +++ b/tests/end-to-end/logging/_files/status/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/logging/_files/status/tests/StatusTest.php b/tests/end-to-end/logging/_files/status/tests/StatusTest.php new file mode 100644 index 00000000000..ad3f7a85c0e --- /dev/null +++ b/tests/end-to-end/logging/_files/status/tests/StatusTest.php @@ -0,0 +1,90 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Basic; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use RuntimeException; + +#[CoversClass('Foo')] +#[UsesClass('Bar')] +#[TestDox('Test result status with and without message')] +class StatusTest extends TestCase +{ + public function testSuccess(): void + { + $this->createMock(AnInterface::class); + + $this->assertTrue(true); + } + + public function testFailure(): void + { + $this->assertTrue(false); + } + + public function testError(): void + { + throw new RuntimeException; + } + + public function testIncomplete(): void + { + $this->markTestIncomplete(); + } + + public function testSkipped(): void + { + $this->markTestSkipped(); + } + + public function testRisky(): void + { + } + + public function testSuccessWithMessage(): void + { + $this->assertTrue(true, 'success with custom message'); + } + + public function testFailureWithMessage(): void + { + $this->assertTrue(false, 'failure with custom message'); + } + + public function testErrorWithMessage(): void + { + throw new RuntimeException('error with custom message'); + } + + public function testIncompleteWithMessage(): void + { + $this->markTestIncomplete('incomplete with custom message'); + } + + #[RequiresPhp('> 9000')] + public function testSkippedByMetadata(): void + { + } + + public function testSkippedWithMessage(): void + { + $this->markTestSkipped('skipped with custom message'); + } + + public function testRiskyWithMessage(): void + { + // Custom messages not implemented for risky status + } +} diff --git a/tests/end-to-end/logging/_files/teamcity-warning/phpunit.xml b/tests/end-to-end/logging/_files/teamcity-warning/phpunit.xml new file mode 100644 index 00000000000..73255515244 --- /dev/null +++ b/tests/end-to-end/logging/_files/teamcity-warning/phpunit.xml @@ -0,0 +1,12 @@ + + + + + tests + + + + bar + diff --git a/tests/end-to-end/logging/_files/teamcity-warning/tests/Test.php b/tests/end-to-end/logging/_files/teamcity-warning/tests/Test.php new file mode 100644 index 00000000000..a2aa00e57b6 --- /dev/null +++ b/tests/end-to-end/logging/_files/teamcity-warning/tests/Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/logging/junit/invalid-path.phpt b/tests/end-to-end/logging/junit/invalid-path.phpt new file mode 100644 index 00000000000..3d990bd7c25 --- /dev/null +++ b/tests/end-to-end/logging/junit/invalid-path.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --log-junit is used with an invalid target path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in JUnit XML format to "": Directory "" does not exist and could not be created + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/junit/invalid-socket.phpt b/tests/end-to-end/logging/junit/invalid-socket.phpt new file mode 100644 index 00000000000..207f32dc7c2 --- /dev/null +++ b/tests/end-to-end/logging/junit/invalid-socket.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --log-junit is used with an invalid socket +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in JUnit XML format to "socket://hostname:port:wrong": "socket://hostname:port:wrong" does not match "socket://hostname:port" format + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/junit/skipped-before-class-method.phpt b/tests/end-to-end/logging/junit/skipped-before-class-method.phpt new file mode 100644 index 00000000000..b4d6d85a334 --- /dev/null +++ b/tests/end-to-end/logging/junit/skipped-before-class-method.phpt @@ -0,0 +1,19 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5354 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + diff --git a/tests/end-to-end/logging/junit/skipped-test-method.phpt b/tests/end-to-end/logging/junit/skipped-test-method.phpt new file mode 100644 index 00000000000..03033bea76b --- /dev/null +++ b/tests/end-to-end/logging/junit/skipped-test-method.phpt @@ -0,0 +1,24 @@ +--TEST-- +JUnit XML: test skipped in test method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + + + + + diff --git a/tests/end-to-end/logging/junit/to-file.phpt b/tests/end-to-end/logging/junit/to-file.phpt new file mode 100644 index 00000000000..3754ea3fc8a --- /dev/null +++ b/tests/end-to-end/logging/junit/to-file.phpt @@ -0,0 +1,70 @@ +--TEST-- +phpunit --log-junit junit.xml _files/StatusTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($logfile); + +unlink($logfile); +--EXPECTF-- + + + + + + PHPUnit\TestFixture\Basic\StatusTest::testFailure%A +Failed asserting that false is true. +%A +%sStatusTest.php:%d + + + PHPUnit\TestFixture\Basic\StatusTest::testError%A +RuntimeException:%w +%A +%sStatusTest.php:%d + + + + + + + + + + + PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage%A +failure with custom message +Failed asserting that false is true. +%A +%sStatusTest.php:%d + + + PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage%A +RuntimeException: error with custom message +%A +%sStatusTest.php:%d + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/junit/to-stdout.phpt b/tests/end-to-end/logging/junit/to-stdout.phpt new file mode 100644 index 00000000000..54014851bed --- /dev/null +++ b/tests/end-to-end/logging/junit/to-stdout.phpt @@ -0,0 +1,64 @@ +--TEST-- +phpunit --log-junit php://stdout _files/StatusTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + + PHPUnit\TestFixture\Basic\StatusTest::testFailure%A +Failed asserting that false is true. +%A +%sStatusTest.php:%d + + + PHPUnit\TestFixture\Basic\StatusTest::testError%A +RuntimeException:%w +%A +%sStatusTest.php:%d + + + + + + + + + + + PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage%A +failure with custom message +Failed asserting that false is true. +%A +%sStatusTest.php:%d + + + PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage%A +RuntimeException: error with custom message +%A +%sStatusTest.php:%d + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/junit/with-progress-with-errors.phpt b/tests/end-to-end/logging/junit/with-progress-with-errors.phpt new file mode 100644 index 00000000000..ac419c988d7 --- /dev/null +++ b/tests/end-to-end/logging/junit/with-progress-with-errors.phpt @@ -0,0 +1,54 @@ +--TEST-- +phpunit --log-junit php://stdout _files/TypeErrorTest.php +--SKIPIF-- +run($_SERVER['argv']); + +print file_get_contents($logfile); + +unlink($logfile); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\TypeErrorTest::testMe +TypeError: Cannot assign DateTime to property PHPUnit\TestFixture\TypeErrorTest::$dateTime of type DateTimeImmutable + +%sTypeErrorTest.php:%d + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. + + + + + PHPUnit\TestFixture\TypeErrorTest::testMe +TypeError: Cannot assign DateTime to property PHPUnit\TestFixture\TypeErrorTest::$dateTime of type DateTimeImmutable + +%sTypeErrorTest.php:%s + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-class-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-class-method.phpt new file mode 100644 index 00000000000..5614da84588 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-class-method.phpt @@ -0,0 +1,62 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInTearDownAfterClassTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-test-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-test-method.phpt new file mode 100644 index 00000000000..926d9cf942f --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-after-test-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInTearDownTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-class-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-class-method.phpt new file mode 100644 index 00000000000..4c2f186c671 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-class-method.phpt @@ -0,0 +1,51 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInSetUpBeforeClassTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + Failed asserting that false is true. + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-test-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-test-method.phpt new file mode 100644 index 00000000000..67908ea8af2 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-before-test-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInSetUpTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-postcondition-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-postcondition-method.phpt new file mode 100644 index 00000000000..a83c8b96b07 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-postcondition-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInPostConditionTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-precondition-method.phpt b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-precondition-method.phpt new file mode 100644 index 00000000000..d67fd293a80 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/assertion-failure-in-precondition-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/AssertionFailureInPreConditionTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument-with-git-information.phpt b/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument-with-git-information.phpt new file mode 100644 index 00000000000..df51235621c --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument-with-git-information.phpt @@ -0,0 +1,234 @@ +--TEST-- +phpunit --log-otr /path/to/logfile --include-git-information ../_files/StatusTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + failure with custom message +Failed asserting that false is true. + + + + + + + + + + + + + + error with custom message + + + + + + + + + + + + + + incomplete with custom message + + + + + + + + + + + + + + PHP > 9000 is required. + + + + + + + + + + + + + skipped with custom message + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument.phpt b/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument.phpt new file mode 100644 index 00000000000..39f083c05e2 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/basic-test-case-class-source-file-as-cli-argument.phpt @@ -0,0 +1,229 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../_files/StatusTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + failure with custom message +Failed asserting that false is true. + + + + + + + + + + + + + + error with custom message + + + + + + + + + + + + + + incomplete with custom message + + + + + + + + + + + + + + PHP > 9000 is required. + + + + + + + + + + + + + skipped with custom message + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/basic-test-suite-from-xml-configuration-file.phpt b/tests/end-to-end/logging/open-test-reporting/basic-test-suite-from-xml-configuration-file.phpt new file mode 100644 index 00000000000..1e131cb125c --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/basic-test-suite-from-xml-configuration-file.phpt @@ -0,0 +1,233 @@ +--TEST-- +phpunit --configuration ../_files/status/phpunit.xml --log-otr /path/to/logfile +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Failed asserting that false is true. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + failure with custom message +Failed asserting that false is true. + + + + + + + + + + + + + + error with custom message + + + + + + + + + + + + + + incomplete with custom message + + + + + + + + + + + + + + PHP > 9000 is required. + + + + + + + + + + + + + skipped with custom message + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/exception-in-after-class-method.phpt b/tests/end-to-end/logging/open-test-reporting/exception-in-after-class-method.phpt new file mode 100644 index 00000000000..f4ed025a9d5 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/exception-in-after-class-method.phpt @@ -0,0 +1,62 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/ExceptionInTearDownAfterClassTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/exception-in-after-test-method.phpt b/tests/end-to-end/logging/open-test-reporting/exception-in-after-test-method.phpt new file mode 100644 index 00000000000..9c4e5511605 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/exception-in-after-test-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/ExceptionInTearDownTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/exception-in-before-class-method.phpt b/tests/end-to-end/logging/open-test-reporting/exception-in-before-class-method.phpt new file mode 100644 index 00000000000..daca167d0f0 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/exception-in-before-class-method.phpt @@ -0,0 +1,51 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/ExceptionInSetUpBeforeClassTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/exception-in-before-test-method.phpt b/tests/end-to-end/logging/open-test-reporting/exception-in-before-test-method.phpt new file mode 100644 index 00000000000..1aa131161fd --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/exception-in-before-test-method.phpt @@ -0,0 +1,60 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/ExceptionInSetUpTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/invalid-path.phpt b/tests/end-to-end/logging/open-test-reporting/invalid-path.phpt new file mode 100644 index 00000000000..f36acb11942 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/invalid-path.phpt @@ -0,0 +1,28 @@ +--TEST-- +phpunit --log-otr /invalid/path ../../event/_files/basic/SuccessTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in Open Test Reporting XML format to "/invalid/path": Unable to resolve file path + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/open-test-reporting/skipped-in-before-class-method.phpt b/tests/end-to-end/logging/open-test-reporting/skipped-in-before-class-method.phpt new file mode 100644 index 00000000000..85fca39c8a0 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/skipped-in-before-class-method.phpt @@ -0,0 +1,47 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/SkippedInSetupBeforeClassTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + message + + + diff --git a/tests/end-to-end/logging/open-test-reporting/skipped-in-before-test-method.phpt b/tests/end-to-end/logging/open-test-reporting/skipped-in-before-test-method.phpt new file mode 100644 index 00000000000..d536ed166a5 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/skipped-in-before-test-method.phpt @@ -0,0 +1,56 @@ +--TEST-- +phpunit --log-otr /path/to/logfile ../../event/_files/SkippedInSetupTest.php +--FILE-- +run($_SERVER['argv']); + +validate_and_print($logfile); + +unlink($logfile); +--EXPECTF-- + + + + %s + %s + %s + %s + %s + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/end-to-end/logging/open-test-reporting/validate_and_print.php b/tests/end-to-end/logging/open-test-reporting/validate_and_print.php new file mode 100644 index 00000000000..18806f61a94 --- /dev/null +++ b/tests/end-to-end/logging/open-test-reporting/validate_and_print.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use const PHP_EOL; +use function file_get_contents; +use function libxml_clear_errors; +use function libxml_get_errors; +use function libxml_use_internal_errors; +use function printf; +use function trim; +use DOMDocument; + +function validate_and_print(string $logfile): void +{ + libxml_use_internal_errors(true); + + $document = new DOMDocument; + $document->load($logfile); + + if (!$document->schemaValidate(__DIR__ . '/../../../../src/Logging/OpenTestReporting/schema/otr.xsd')) { + print 'Generated XML document does not validate against Open Test Reporting schemas:' . PHP_EOL . PHP_EOL; + + foreach (libxml_get_errors() as $error) { + printf( + '- Line %d: %s' . PHP_EOL, + $error->line, + trim($error->message), + ); + } + + print PHP_EOL; + } + + libxml_clear_errors(); + + print file_get_contents($logfile); +} diff --git a/tests/end-to-end/logging/teamcity/log-teamcity-comparisonfailure.phpt b/tests/end-to-end/logging/teamcity/log-teamcity-comparisonfailure.phpt new file mode 100644 index 00000000000..9dfab66f197 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/log-teamcity-comparisonfailure.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit --log-teamcity php://stdout ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='1' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\ComparisonFailureTest' locationHint='php_qn:%sComparisonFailureTest.php::\PHPUnit\TestFixture\ComparisonFailureTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='php_qn:%sComparisonFailureTest.php::\PHPUnit\TestFixture\ComparisonFailureTest::testOne' flowId='%d'] +##teamcity[testFailed name='testOne' message='Failed asserting that false matches expected true.' details='%sComparisonFailureTest.php:%d|n' duration='%s' type='comparisonFailure' actual='false' expected='true' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%s' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\ComparisonFailureTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/log-teamcity-invalid-path.phpt b/tests/end-to-end/logging/teamcity/log-teamcity-invalid-path.phpt new file mode 100644 index 00000000000..262a9d9bce1 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/log-teamcity-invalid-path.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --log-teamcity is used with an invalid target path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TeamCity format to "": Directory "" does not exist and could not be created + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/teamcity/log-teamcity-invalid-socket.phpt b/tests/end-to-end/logging/teamcity/log-teamcity-invalid-socket.phpt new file mode 100644 index 00000000000..259039b2fef --- /dev/null +++ b/tests/end-to-end/logging/teamcity/log-teamcity-invalid-socket.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --log-teamcity is used with an invalid socket +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TeamCity format to "socket://hostname:port:wrong": "socket://hostname:port:wrong" does not match "socket://hostname:port" format + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/teamcity/log-teamcity.phpt b/tests/end-to-end/logging/teamcity/log-teamcity.phpt new file mode 100644 index 00000000000..0b0efd9078e --- /dev/null +++ b/tests/end-to-end/logging/teamcity/log-teamcity.phpt @@ -0,0 +1,53 @@ +--TEST-- +phpunit --log-teamcity php://stdout ../../basic/unit/StatusTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='13' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\StatusTest' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] +##teamcity[testStarted name='testSuccess' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccess' flowId='%d'] +##teamcity[testFinished name='testSuccess' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailure' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailure' flowId='%d'] +##teamcity[testFailed name='testFailure' message='Failed asserting that false is true.' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailure' duration='%d' flowId='%d'] +##teamcity[testStarted name='testError' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testError' flowId='%d'] +##teamcity[testFailed name='testError' message='RuntimeException' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testError' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncomplete' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncomplete' flowId='%d'] +##teamcity[testIgnored name='testIncomplete' message='' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncomplete' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkipped' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkipped' flowId='%d'] +##teamcity[testIgnored name='testSkipped' message='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkipped' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRisky' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRisky' flowId='%d'] +##teamcity[testFailed name='testRisky' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRisky' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSuccessWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccessWithMessage' flowId='%d'] +##teamcity[testFinished name='testSuccessWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailureWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage' flowId='%d'] +##teamcity[testFailed name='testFailureWithMessage' message='failure with custom message|nFailed asserting that false is true.' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailureWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testErrorWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage' flowId='%d'] +##teamcity[testFailed name='testErrorWithMessage' message='RuntimeException: error with custom message' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testErrorWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncompleteWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncompleteWithMessage' flowId='%d'] +##teamcity[testIgnored name='testIncompleteWithMessage' message='incomplete with custom message' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncompleteWithMessage' duration='%d' flowId='%d'] +##teamcity[testIgnored name='testSkippedByMetadata' message='PHP > 9000 is required.' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkippedWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkippedWithMessage' flowId='%d'] +##teamcity[testIgnored name='testSkippedWithMessage' message='skipped with custom message' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkippedWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRiskyWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRiskyWithMessage' flowId='%d'] +##teamcity[testFailed name='testRiskyWithMessage' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRiskyWithMessage' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-data-provider.phpt b/tests/end-to-end/logging/teamcity/teamcity-data-provider.phpt new file mode 100644 index 00000000000..303d35ba6d9 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-data-provider.phpt @@ -0,0 +1,38 @@ +--TEST-- +phpunit --teamcity _files/DataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TeamCity\DataProviderTest' locationHint='php_qn://%sDataProviderTest.php::\PHPUnit\TestFixture\TeamCity\DataProviderTest' flowId='%d'] +##teamcity[testSuiteStarted name='testOne' locationHint='php_qn://%sDataProviderTest.php::\PHPUnit\TestFixture\TeamCity\DataProviderTest::testOne' flowId='%d'] +##teamcity[testStarted name='testOne with data set #0' locationHint='php_qn://%sDataProviderTest.php::\PHPUnit\TestFixture\TeamCity\DataProviderTest::testOne with data set #0' flowId='%d'] +##teamcity[testFinished name='testOne with data set #0' duration='%d' flowId='%d'] +##teamcity[testStarted name='testOne with data set #1' locationHint='php_qn://%sDataProviderTest.php::\PHPUnit\TestFixture\TeamCity\DataProviderTest::testOne with data set #1' flowId='%d'] +##teamcity[testFailed name='testOne with data set #1' message='Failed asserting that false is true.' details='%sDataProviderTest.php:28|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne with data set #1' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='testOne' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TeamCity\DataProviderTest' flowId='%d'] +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\TeamCity\DataProviderTest::testOne#1 with data (false) +Failed asserting that false is true. + +%sDataProviderTest.php:28 + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/logging/teamcity/teamcity-directory.phpt b/tests/end-to-end/logging/teamcity/teamcity-directory.phpt new file mode 100644 index 00000000000..03d9afb00dd --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-directory.phpt @@ -0,0 +1,136 @@ +--TEST-- +phpunit --teamcity ../../basic/unit/ +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +##teamcity[testCount count='19' flowId='%d'] +##teamcity[testSuiteStarted name='CLI Arguments' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\SetUpBeforeClassTest' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eSetUpBeforeClassTest.php::\PHPUnit\TestFixture\Basic\SetUpBeforeClassTest' flowId='%d'] +##teamcity[testFailed name='PHPUnit\TestFixture\Basic\SetUpBeforeClassTest' message='Exception: forcing an Exception in setUpBeforeClass()' details='%stests%eend-to-end%e_files%ebasic%eunit%eSetUpBeforeClassTest.php:32|n' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\SetUpBeforeClassTest' message='Exception: forcing an Exception in setUpBeforeClass()' details='%stests%eend-to-end%e_files%ebasic%eunit%eSetUpBeforeClassTest.php:32|n' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\SetUpBeforeClassTest' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\SetUpTest' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eSetUpTest.php::\PHPUnit\TestFixture\Basic\SetUpTest' flowId='%d'] +##teamcity[testFailed name='testOneWithSetUpException' message='RuntimeException: throw exception in setUp' details='%stests%eend-to-end%e_files%ebasic%eunit%eSetUpTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFailed name='testTwoWithSetUpException' message='RuntimeException: throw exception in setUp' details='%stests%eend-to-end%e_files%ebasic%eunit%eSetUpTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\SetUpTest' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\StatusTest' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] +##teamcity[testStarted name='testSuccess' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccess' flowId='%d'] +##teamcity[testFinished name='testSuccess' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailure' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailure' flowId='%d'] +##teamcity[testFailed name='testFailure' message='Failed asserting that false is true.' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailure' duration='%d' flowId='%d'] +##teamcity[testStarted name='testError' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testError' flowId='%d'] +##teamcity[testFailed name='testError' message='RuntimeException' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testError' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncomplete' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncomplete' flowId='%d'] +##teamcity[testIgnored name='testIncomplete' message='' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncomplete' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkipped' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkipped' flowId='%d'] +##teamcity[testIgnored name='testSkipped' message='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkipped' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRisky' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRisky' flowId='%d'] +##teamcity[testFailed name='testRisky' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRisky' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSuccessWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccessWithMessage' flowId='%d'] +##teamcity[testFinished name='testSuccessWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailureWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage' flowId='%d'] +##teamcity[testFailed name='testFailureWithMessage' message='failure with custom message|nFailed asserting that false is true.' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailureWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testErrorWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage' flowId='%d'] +##teamcity[testFailed name='testErrorWithMessage' message='RuntimeException: error with custom message' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testErrorWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncompleteWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncompleteWithMessage' flowId='%d'] +##teamcity[testIgnored name='testIncompleteWithMessage' message='incomplete with custom message' details='%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncompleteWithMessage' duration='%d' flowId='%d'] +##teamcity[testIgnored name='testSkippedByMetadata' message='PHP > 9000 is required.' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkippedWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkippedWithMessage' flowId='%d'] +##teamcity[testIgnored name='testSkippedWithMessage' message='skipped with custom message' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkippedWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRiskyWithMessage' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRiskyWithMessage' flowId='%d'] +##teamcity[testFailed name='testRiskyWithMessage' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRiskyWithMessage' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\TearDownAfterClassTest' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eTearDownAfterClassTest.php::\PHPUnit\TestFixture\Basic\TearDownAfterClassTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eTearDownAfterClassTest.php::\PHPUnit\TestFixture\Basic\TearDownAfterClassTest::testOne' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='php_qn://%stests%eend-to-end%e_files%ebasic%eunit%eTearDownAfterClassTest.php::\PHPUnit\TestFixture\Basic\TearDownAfterClassTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\TearDownAfterClassTest' flowId='%d'] +##teamcity[testSuiteFinished name='CLI Arguments' flowId='%d'] +Time: %s, Memory: %s + +There were 6 errors: + +1) PHPUnit\TestFixture\Basic\SetUpBeforeClassTest +Exception: forcing an Exception in setUpBeforeClass() + +%s%eSetUpBeforeClassTest.php:%d + +2) PHPUnit\TestFixture\Basic\SetUpTest::testOneWithSetUpException +RuntimeException: throw exception in setUp + +%s%eSetUpTest.php:%d + +3) PHPUnit\TestFixture\Basic\SetUpTest::testTwoWithSetUpException +RuntimeException: throw exception in setUp + +%s%eSetUpTest.php:%d + +4) PHPUnit\TestFixture\Basic\StatusTest::testError +RuntimeException: + +%s%eStatusTest.php:%d + +5) PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage +RuntimeException: error with custom message + +%s%eStatusTest.php:%d + +6) PHPUnit\TestFixture\Basic\TearDownAfterClassTest +Exception: forcing an Exception in tearDownAfterClass() + +%s%eTearDownAfterClassTest.php:%d + +-- + +There were 2 failures: + +1) PHPUnit\TestFixture\Basic\StatusTest::testFailure +Failed asserting that false is true. + +%s%eStatusTest.php:%d + +2) PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage +failure with custom message +Failed asserting that false is true. + +%s%eStatusTest.php:%d + +-- + +There were 2 risky tests: + +1) PHPUnit\TestFixture\Basic\StatusTest::testRisky +This test did not perform any assertions + +%s%eStatusTest.php:%d + +2) PHPUnit\TestFixture\Basic\StatusTest::testRiskyWithMessage +This test did not perform any assertions + +%s%eStatusTest.php:%d + +ERRORS! +Tests: 18, Assertions: 6, Errors: 6, Failures: 2, Skipped: 3, Incomplete: 2, Risky: 2. diff --git a/tests/end-to-end/logging/teamcity/teamcity-file.phpt b/tests/end-to-end/logging/teamcity/teamcity-file.phpt new file mode 100644 index 00000000000..bd21ba11f1f --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-file.phpt @@ -0,0 +1,100 @@ +--TEST-- +phpunit --teamcity ../../basic/unit/StatusTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +##teamcity[testCount count='13' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Basic\StatusTest' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] +##teamcity[testStarted name='testSuccess' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccess' flowId='%d'] +##teamcity[testFinished name='testSuccess' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailure' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailure' flowId='%d'] +##teamcity[testFailed name='testFailure' message='Failed asserting that false is true.' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailure' duration='%d' flowId='%d'] +##teamcity[testStarted name='testError' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testError' flowId='%d'] +##teamcity[testFailed name='testError' message='RuntimeException' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testError' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncomplete' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncomplete' flowId='%d'] +##teamcity[testIgnored name='testIncomplete' message='' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncomplete' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkipped' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkipped' flowId='%d'] +##teamcity[testIgnored name='testSkipped' message='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkipped' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRisky' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRisky' flowId='%d'] +##teamcity[testFailed name='testRisky' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRisky' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSuccessWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSuccessWithMessage' flowId='%d'] +##teamcity[testFinished name='testSuccessWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testFailureWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage' flowId='%d'] +##teamcity[testFailed name='testFailureWithMessage' message='failure with custom message|nFailed asserting that false is true.' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testFailureWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testErrorWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage' flowId='%d'] +##teamcity[testFailed name='testErrorWithMessage' message='RuntimeException: error with custom message' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testErrorWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testIncompleteWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testIncompleteWithMessage' flowId='%d'] +##teamcity[testIgnored name='testIncompleteWithMessage' message='incomplete with custom message' details='%sStatusTest.php:%d|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testIncompleteWithMessage' duration='%d' flowId='%d'] +##teamcity[testIgnored name='testSkippedByMetadata' message='PHP > 9000 is required.' duration='%d' flowId='%d'] +##teamcity[testStarted name='testSkippedWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testSkippedWithMessage' flowId='%d'] +##teamcity[testIgnored name='testSkippedWithMessage' message='skipped with custom message' duration='%d' flowId='%d'] +##teamcity[testFinished name='testSkippedWithMessage' duration='%d' flowId='%d'] +##teamcity[testStarted name='testRiskyWithMessage' locationHint='php_qn://%sStatusTest.php::\PHPUnit\TestFixture\Basic\StatusTest::testRiskyWithMessage' flowId='%d'] +##teamcity[testFailed name='testRiskyWithMessage' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testRiskyWithMessage' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Basic\StatusTest' flowId='%d'] +Time: %s, Memory: %s + +There were 2 errors: + +1) PHPUnit\TestFixture\Basic\StatusTest::testError +RuntimeException: + +%s%eStatusTest.php:%d + +2) PHPUnit\TestFixture\Basic\StatusTest::testErrorWithMessage +RuntimeException: error with custom message + +%s%eStatusTest.php:%d + +-- + +There were 2 failures: + +1) PHPUnit\TestFixture\Basic\StatusTest::testFailure +Failed asserting that false is true. + +%s%eStatusTest.php:%d + +2) PHPUnit\TestFixture\Basic\StatusTest::testFailureWithMessage +failure with custom message +Failed asserting that false is true. + +%s%eStatusTest.php:%d + +-- + +There were 2 risky tests: + +1) PHPUnit\TestFixture\Basic\StatusTest::testRisky +This test did not perform any assertions + +%s%eStatusTest.php:%d + +2) PHPUnit\TestFixture\Basic\StatusTest::testRiskyWithMessage +This test did not perform any assertions + +%s%eStatusTest.php:%d + +ERRORS! +Tests: 13, Assertions: 4, Errors: 2, Failures: 2, Skipped: 3, Incomplete: 2, Risky: 2. diff --git a/tests/end-to-end/logging/teamcity/teamcity-inner-exceptions.phpt b/tests/end-to-end/logging/teamcity/teamcity-inner-exceptions.phpt new file mode 100644 index 00000000000..487b9e50b63 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-inner-exceptions.phpt @@ -0,0 +1,25 @@ +--TEST-- +phpunit --log-teamcity php://stdout ../../_files/ExceptionStackTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\ExceptionStackTest' locationHint='php_qn://%s%etests%e_files%eExceptionStackTest.php::\PHPUnit\TestFixture\ExceptionStackTest' flowId='%d'] +##teamcity[testStarted name='testPrintingChildException' locationHint='php_qn://%s%etests%e_files%eExceptionStackTest.php::\PHPUnit\TestFixture\ExceptionStackTest::testPrintingChildException' flowId='%d'] +##teamcity[testFailed name='testPrintingChildException' message='Child exception|nmessage|nFailed asserting that two arrays are equal.|n--- Expected|n+++ Actual|n@@ @@|n Array (|n- 0 => 1|n+ 0 => 2|n )|n' details='%s%etests%e_files%eExceptionStackTest.php:27|n|nCaused by|nmessage|nFailed asserting that two arrays are equal.|n--- Expected|n+++ Actual|n@@ @@|n Array (|n- 0 => 1|n+ 0 => 2|n )|n|n%s%etests%e_files%eExceptionStackTest.php:23|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testPrintingChildException' duration='%d' flowId='%d'] +##teamcity[testStarted name='testNestedExceptions' locationHint='php_qn://%s%etests%e_files%eExceptionStackTest.php::\PHPUnit\TestFixture\ExceptionStackTest::testNestedExceptions' flowId='%d'] +##teamcity[testFailed name='testNestedExceptions' message='Exception: One' details='%s%etests%e_files%eExceptionStackTest.php:35|n|nCaused by|nInvalidArgumentException: Two|n|n%s%etests%e_files%eExceptionStackTest.php:34|n|nCaused by|nException: Three|n|n%s%etests%e_files%eExceptionStackTest.php:33|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testNestedExceptions' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\ExceptionStackTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-deprecation.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-deprecation.phpt new file mode 100644 index 00000000000..9aee5a41262 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-deprecation.phpt @@ -0,0 +1,25 @@ +--TEST-- +TeamCity: print deprecation message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='%d' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest' locationHint='%sDeprecationTest.php::\PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sDeprecationTest.php::\PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testOne' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sDeprecationTest.php::\PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testStarted name='testThree' locationHint='php_qn:%sDeprecationTest.php::\PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest::testThree' flowId='%d'] +##teamcity[testFinished name='testThree' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\DeprecationTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-error.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-error.phpt new file mode 100644 index 00000000000..ee97b1af979 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-error.phpt @@ -0,0 +1,24 @@ +--TEST-- +TeamCity: print error message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\ErrorTest' locationHint='%sErrorTest.php::\PHPUnit\TestFixture\TestRunnerStopping\ErrorTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sErrorTest.php::\PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testOne' flowId='%d'] +##teamcity[testFailed name='testOne' message='Exception: message' details='%sErrorTest.php:19|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sErrorTest.php::\PHPUnit\TestFixture\TestRunnerStopping\ErrorTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\ErrorTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-failure.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-failure.phpt new file mode 100644 index 00000000000..1cd2b680011 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-failure.phpt @@ -0,0 +1,23 @@ +--TEST-- +TeamCity: print failure message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='%d' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\FailureTest' locationHint='%sFailureTest.php::\PHPUnit\TestFixture\TestRunnerStopping\FailureTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sFailureTest.php::\PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testOne' flowId='%d'] +##teamcity[testFailed name='testOne' message='Failed asserting that false is true.' details='%sFailureTest.php:18|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sFailureTest.php::\PHPUnit\TestFixture\TestRunnerStopping\FailureTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\FailureTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-incomplete.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-incomplete.phpt new file mode 100644 index 00000000000..79ed061ba0a --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-incomplete.phpt @@ -0,0 +1,24 @@ +--TEST-- +TeamCity: print incomplete message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest' locationHint='%sIncompleteTest.php::\PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sIncompleteTest.php::\PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testOne' flowId='%d'] +##teamcity[testIgnored name='testOne' message='message' details='%sIncompleteTest.php:18|n' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sIncompleteTest.php::\PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\IncompleteTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-notice.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-notice.phpt new file mode 100644 index 00000000000..7dc22aeaab0 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-notice.phpt @@ -0,0 +1,23 @@ +--TEST-- +TeamCity: print notice message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\NoticeTest' locationHint='%sNoticeTest.php::\PHPUnit\TestFixture\TestRunnerStopping\NoticeTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sNoticeTest.php::\PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testOne' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sNoticeTest.php::\PHPUnit\TestFixture\TestRunnerStopping\NoticeTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\NoticeTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-risky.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-risky.phpt new file mode 100644 index 00000000000..bac507578c3 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-risky.phpt @@ -0,0 +1,23 @@ +--TEST-- +TeamCity: print risky message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\RiskyTest' locationHint='%sRiskyTest.php::\PHPUnit\TestFixture\TestRunnerStopping\RiskyTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sRiskyTest.php::\PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testOne' flowId='%d'] +##teamcity[testFailed name='testOne' message='This test did not perform any assertions' details='' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sRiskyTest.php::\PHPUnit\TestFixture\TestRunnerStopping\RiskyTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\RiskyTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-skipped-before-class.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-skipped-before-class.phpt new file mode 100644 index 00000000000..3049779f431 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-skipped-before-class.phpt @@ -0,0 +1,19 @@ +--TEST-- +TeamCity: test skipped in before-class method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='1' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\SkippedBeforeClassTest' locationHint='php_qn:%sSkippedBeforeClassTest.php::\PHPUnit\TestFixture\TestRunnerStopping\SkippedBeforeClassTest' flowId='%d'] +##teamcity[testIgnored name='PHPUnit\TestFixture\TestRunnerStopping\SkippedBeforeClassTest' message='message' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\SkippedBeforeClassTest' message='message' duration='%d' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-skipped.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-skipped.phpt new file mode 100644 index 00000000000..13ded3d259e --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-skipped.phpt @@ -0,0 +1,23 @@ +--TEST-- +TeamCity: test skipped in test method +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\SkippedTest' locationHint='%sSkippedTest.php::\PHPUnit\TestFixture\TestRunnerStopping\SkippedTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sSkippedTest.php::\PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testOne' flowId='%d'] +##teamcity[testIgnored name='testOne' message='message' duration='%d' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sSkippedTest.php::\PHPUnit\TestFixture\TestRunnerStopping\SkippedTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\SkippedTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-print-warning.phpt b/tests/end-to-end/logging/teamcity/teamcity-print-warning.phpt new file mode 100644 index 00000000000..cc6530e37d4 --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-print-warning.phpt @@ -0,0 +1,23 @@ +--TEST-- +TeamCity: print warning message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +##teamcity[testCount count='2' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\TestRunnerStopping\WarningTest' locationHint='%sWarningTest.php::\PHPUnit\TestFixture\TestRunnerStopping\WarningTest' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='%sWarningTest.php::\PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testOne' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%d' flowId='%d'] +##teamcity[testStarted name='testTwo' locationHint='%sWarningTest.php::\PHPUnit\TestFixture\TestRunnerStopping\WarningTest::testTwo' flowId='%d'] +##teamcity[testFinished name='testTwo' duration='%d' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\TestRunnerStopping\WarningTest' flowId='%d'] diff --git a/tests/end-to-end/logging/teamcity/teamcity-warning.phpt b/tests/end-to-end/logging/teamcity/teamcity-warning.phpt new file mode 100644 index 00000000000..6ec0cd946aa --- /dev/null +++ b/tests/end-to-end/logging/teamcity/teamcity-warning.phpt @@ -0,0 +1,39 @@ +--TEST-- +phpunit --teamcity ../../basic/unit/StatusTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +##teamcity[testCount count='1' flowId='%d'] +##teamcity[testSuiteStarted name='%s%etests%eend-to-end%elogging%e_files%eteamcity-warning%ephpunit.xml' flowId='%d'] +##teamcity[testSuiteStarted name='default' flowId='%d'] +##teamcity[testSuiteStarted name='PHPUnit\TestFixture\Test' locationHint='php_qn://%s%eteamcity-warning%etests%eTest.php::\PHPUnit\TestFixture\Test' flowId='%d'] +##teamcity[testStarted name='testOne' locationHint='php_qn://%s%eteamcity-warning%etests%eTest.php::\PHPUnit\TestFixture\Test::testOne' flowId='%d'] +##teamcity[testFinished name='testOne' duration='%s' flowId='%d'] +##teamcity[testSuiteFinished name='PHPUnit\TestFixture\Test' flowId='%d'] +##teamcity[testSuiteFinished name='default' flowId='%d'] +##teamcity[testSuiteFinished name='%s%etests%eend-to-end%elogging%e_files%eteamcity-warning%ephpunit.xml' flowId='%d'] +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Test results may not be as expected because the XML configuration file did not pass validation: + + Line 11: + - Element 'foo': This element is not expected. + + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-case-with-dollar-sign.phpt b/tests/end-to-end/logging/testdox/testdox-case-with-dollar-sign.phpt new file mode 100644 index 00000000000..16f28d0da1d --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-case-with-dollar-sign.phpt @@ -0,0 +1,28 @@ +--TEST-- +Testdox: output containing dollar signs in the value from data provider +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.... 4 / 4 (100%) + +Time: %s, Memory: %s + +Case With Dollar Sign (PHPUnit\TestFixture\CaseWithDollarSign) + ✔ The "$12.34" is used for this test + ✔ The "Some text before the price $5.67" is used for this test + ✔ The "Dollar sign followed by letter $Q" is used for this test + ✔ The "Alone $ surrounded by spaces" is used for this test + +OK (4 tests, 4 assertions) diff --git a/tests/end-to-end/logging/testdox/testdox-html-invalid-path.phpt b/tests/end-to-end/logging/testdox/testdox-html-invalid-path.phpt new file mode 100644 index 00000000000..c9586fd5fed --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-html-invalid-path.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --testdox-html is used with an invalid target path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TestDox HTML format to "": Directory "" does not exist and could not be created + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-html-invalid-socket.phpt b/tests/end-to-end/logging/testdox/testdox-html-invalid-socket.phpt new file mode 100644 index 00000000000..60c404f6c61 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-html-invalid-socket.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --testdox-html is used with an invalid socket +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TestDox HTML format to "socket://hostname:port:wrong": "socket://hostname:port:wrong" does not match "socket://hostname:port" format + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-html.phpt b/tests/end-to-end/logging/testdox/testdox-html.phpt new file mode 100644 index 00000000000..987277e2c07 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-html.phpt @@ -0,0 +1,81 @@ +--TEST-- +phpunit --testdox-html php://stdout ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($output); + +unlink($output); +--EXPECTF-- + + + + + Test Documentation + + + +

    Bank Account (PHPUnit\TestFixture\BankAccount)

    +
      +
    • Balance is initially zero
    • +
    • Balance cannot become negative
    • +
    + + diff --git a/tests/end-to-end/logging/testdox/testdox-print-deprecation.phpt b/tests/end-to-end/logging/testdox/testdox-print-deprecation.phpt new file mode 100644 index 00000000000..fb6c33b5e1c --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-deprecation.phpt @@ -0,0 +1,20 @@ +--TEST-- +Testdox: print deprecation message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Deprecation (PHPUnit\TestFixture\TestRunnerStopping\Deprecation) + [x] One + [x] Two + [x] Three diff --git a/tests/end-to-end/logging/testdox/testdox-print-error.phpt b/tests/end-to-end/logging/testdox/testdox-print-error.phpt new file mode 100644 index 00000000000..9e1036a7b4e --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-error.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testdox: print error message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Error (PHPUnit\TestFixture\TestRunnerStopping\Error) + [ ] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-failure.phpt b/tests/end-to-end/logging/testdox/testdox-print-failure.phpt new file mode 100644 index 00000000000..ae968326d3e --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-failure.phpt @@ -0,0 +1,18 @@ +--TEST-- +Testdox: print failure message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Failure (PHPUnit\TestFixture\TestRunnerStopping\Failure) + [ ] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-incomplete.phpt b/tests/end-to-end/logging/testdox/testdox-print-incomplete.phpt new file mode 100644 index 00000000000..bd74a312e32 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-incomplete.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testdox: print incomplete message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Incomplete (PHPUnit\TestFixture\TestRunnerStopping\Incomplete) + [ ] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-notice.phpt b/tests/end-to-end/logging/testdox/testdox-print-notice.phpt new file mode 100644 index 00000000000..e1e2f4c3c96 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-notice.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testdox: print notice message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Notice (PHPUnit\TestFixture\TestRunnerStopping\Notice) + [x] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-previous-exception-colorized.phpt b/tests/end-to-end/logging/testdox/testdox-print-previous-exception-colorized.phpt new file mode 100644 index 00000000000..f16c74e95ef --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-previous-exception-colorized.phpt @@ -0,0 +1,41 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5863 +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s + +Time: %s, Memory: %s + +Throws With Previous Exception (PHPUnit\TestFixture\ThrowsWithPreviousException) + ✘ Foo + ┐ + ├ Exception: Outer + │ + │ %sThrowsWithPreviousExceptionTest.php:%d%A + │ Caused by: + ├ Exception: Inner + │ + │ %sThrowsWithPreviousExceptionTest.php:%d%A + ┴ + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-print-previous-exception.phpt b/tests/end-to-end/logging/testdox/testdox-print-previous-exception.phpt new file mode 100644 index 00000000000..0d7125833f1 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-previous-exception.phpt @@ -0,0 +1,37 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5863 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +Throws With Previous Exception (PHPUnit\TestFixture\ThrowsWithPreviousException) + ✘ Foo + │ + │ Exception: Outer + │ + │ %sThrowsWithPreviousExceptionTest.php:%d + │ + │ Caused by: + │ Exception: Inner + │ + │ %sThrowsWithPreviousExceptionTest.php:%d + │ + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-print-risky.phpt b/tests/end-to-end/logging/testdox/testdox-print-risky.phpt new file mode 100644 index 00000000000..d9e76790a43 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-risky.phpt @@ -0,0 +1,18 @@ +--TEST-- +Testdox: print risky message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Risky (PHPUnit\TestFixture\TestRunnerStopping\Risky) + [x] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-skipped.phpt b/tests/end-to-end/logging/testdox/testdox-print-skipped.phpt new file mode 100644 index 00000000000..84d7bcf22b5 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-skipped.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testdox: print skipped message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Skipped (PHPUnit\TestFixture\TestRunnerStopping\Skipped) + [ ] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-print-warning.phpt b/tests/end-to-end/logging/testdox/testdox-print-warning.phpt new file mode 100644 index 00000000000..c2b74136aa9 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-print-warning.phpt @@ -0,0 +1,19 @@ +--TEST-- +Testdox: print warning message +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +Warning (PHPUnit\TestFixture\TestRunnerStopping\Warning) + [x] One + [x] Two diff --git a/tests/end-to-end/logging/testdox/testdox-text-invalid-path.phpt b/tests/end-to-end/logging/testdox/testdox-text-invalid-path.phpt new file mode 100644 index 00000000000..aaaeff0728a --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-text-invalid-path.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --testdox-text is used with an invalid target path +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TestDox plain text format to "": Directory "" does not exist and could not be created + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-text-invalid-socket.phpt b/tests/end-to-end/logging/testdox/testdox-text-invalid-socket.phpt new file mode 100644 index 00000000000..f8c558aee30 --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-text-invalid-socket.phpt @@ -0,0 +1,28 @@ +--TEST-- +Test runner emits warning when --testdox-text is used with an invalid socket +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Cannot log test results in TestDox plain text format to "socket://hostname:port:wrong": "socket://hostname:port:wrong" does not match "socket://hostname:port" format + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/logging/testdox/testdox-text.phpt b/tests/end-to-end/logging/testdox/testdox-text.phpt new file mode 100644 index 00000000000..cadd880e23a --- /dev/null +++ b/tests/end-to-end/logging/testdox/testdox-text.phpt @@ -0,0 +1,24 @@ +--TEST-- +phpunit --testdox-text php://stdout ../../_files/BankAccountTest.php +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($output); + +unlink($output); +--EXPECTF-- +Bank Account (PHPUnit\TestFixture\BankAccount) + [x] Balance is initially zero + [x] Balance cannot become negative diff --git a/tests/end-to-end/metadata/before-test-method-configured-with-attribute.phpt b/tests/end-to-end/metadata/before-test-method-configured-with-attribute.phpt new file mode 100644 index 00000000000..c16340e0e40 --- /dev/null +++ b/tests/end-to-end/metadata/before-test-method-configured-with-attribute.phpt @@ -0,0 +1,32 @@ +--TEST-- +The right events are emitted in the right order for a successful test that has a before-test method that is configured with attribute +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest, 1 test) +Test Preparation Started (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::testOne) +Before Test Method Called (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::beforeMethod) +Before Test Method Finished: +- PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::beforeMethod +Test Prepared (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::testOne) +Test Passed (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::testOne) +Test Finished (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest::testOne) +Test Suite Finished (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithAttributeTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/metadata/before-test-method-configured-with-prioritized-attribute.phpt b/tests/end-to-end/metadata/before-test-method-configured-with-prioritized-attribute.phpt new file mode 100644 index 00000000000..81d37999619 --- /dev/null +++ b/tests/end-to-end/metadata/before-test-method-configured-with-prioritized-attribute.phpt @@ -0,0 +1,36 @@ +--TEST-- +The right events are emitted in the right order for a successful test that has a before-test method that is configured with attribute +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest, 1 test) +Test Preparation Started (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::testOne) +Before Test Method Called (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::beforeMethodWithHighPriority) +Before Test Method Called (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::setUp) +Before Test Method Called (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::beforeMethodWithLowPriority) +Before Test Method Finished: +- PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::beforeMethodWithHighPriority +- PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::setUp +- PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::beforeMethodWithLowPriority +Test Prepared (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::testOne) +Test Passed (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::testOne) +Test Finished (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest::testOne) +Test Suite Finished (PHPUnit\DeprecatedAnnotationsTestFixture\BeforeTestMethodWithPrioritizedAttributeTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/metadata/hook-methods-order.phpt b/tests/end-to-end/metadata/hook-methods-order.phpt new file mode 100644 index 00000000000..dd5ba156680 --- /dev/null +++ b/tests/end-to-end/metadata/hook-methods-order.phpt @@ -0,0 +1,58 @@ +--TEST-- +The right events are emitted in the right order for a successful test that has a before-test method that is configured with annotation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sHookMethodsOrderTestCase.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\HookMethodsOrderTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\HookMethodsOrderTest::testOne) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::beforeWithPriorityInParent) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::beforeWithPriority) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::beforeInParent) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::beforeFirst) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::beforeSecond) +Before Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\HookMethodsOrderTest::beforeWithPriorityInParent +- PHPUnit\TestFixture\HookMethodsOrderTest::beforeWithPriority +- PHPUnit\TestFixture\HookMethodsOrderTest::beforeInParent +- PHPUnit\TestFixture\HookMethodsOrderTest::beforeFirst +- PHPUnit\TestFixture\HookMethodsOrderTest::beforeSecond +- PHPUnit\TestFixture\HookMethodsOrderTest::setUp +Test Prepared (PHPUnit\TestFixture\HookMethodsOrderTest::testOne) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::afterWithPriority) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::afterWithPriorityInParent) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::tearDown) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::afterFirst) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::afterSecond) +After Test Method Called (PHPUnit\TestFixture\HookMethodsOrderTest::afterInParent) +After Test Method Finished: +- PHPUnit\TestFixture\HookMethodsOrderTest::afterWithPriority +- PHPUnit\TestFixture\HookMethodsOrderTest::afterWithPriorityInParent +- PHPUnit\TestFixture\HookMethodsOrderTest::tearDown +- PHPUnit\TestFixture\HookMethodsOrderTest::afterFirst +- PHPUnit\TestFixture\HookMethodsOrderTest::afterSecond +- PHPUnit\TestFixture\HookMethodsOrderTest::afterInParent +Test Passed (PHPUnit\TestFixture\HookMethodsOrderTest::testOne) +Test Finished (PHPUnit\TestFixture\HookMethodsOrderTest::testOne) +Test Suite Finished (PHPUnit\TestFixture\HookMethodsOrderTest, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/metadata/mix-attribute-dataproviders.phpt b/tests/end-to-end/metadata/mix-attribute-dataproviders.phpt new file mode 100644 index 00000000000..b15a5f09901 --- /dev/null +++ b/tests/end-to-end/metadata/mix-attribute-dataproviders.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../_files/TestDataProviderExternalAndDataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/metadata/mix-test-with-dataproviders.phpt b/tests/end-to-end/metadata/mix-test-with-dataproviders.phpt new file mode 100644 index 00000000000..f451bf43596 --- /dev/null +++ b/tests/end-to-end/metadata/mix-test-with-dataproviders.phpt @@ -0,0 +1,21 @@ +--TEST-- +phpunit ../_files/TestWithAndTestWithJsonDataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/metadata/requires-environment-variable.phpt b/tests/end-to-end/metadata/requires-environment-variable.phpt new file mode 100644 index 00000000000..50d88ab98df --- /dev/null +++ b/tests/end-to-end/metadata/requires-environment-variable.phpt @@ -0,0 +1,36 @@ +--TEST-- +Tests are correctly ran based on environment variables requirements +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +SSS.... 7 / 7 (100%) + +Time: %s, Memory: %s + +There were 3 skipped tests: + +1) PHPUnit\TestFixture\requires_environment_variable\SomeTest::testShouldNotRunFOOHasWrongValue +Environment variable "FOO" is required to be "bar". + +2) PHPUnit\TestFixture\requires_environment_variable\SomeTest::testShouldNotRunBARIsEmpty +Environment variable "BAR" is required. + +3) PHPUnit\TestFixture\requires_environment_variable\SomeTest::testShouldNotRunBAZDoesNotExist +Environment variable "BAZ" is required. + +OK, but some tests were skipped! +Tests: 7, Assertions: 4, Skipped: 3. + diff --git a/tests/end-to-end/metadata/warning-covers-and-coversnothing-are-used.phpt b/tests/end-to-end/metadata/warning-covers-and-coversnothing-are-used.phpt new file mode 100644 index 00000000000..b15db084260 --- /dev/null +++ b/tests/end-to-end/metadata/warning-covers-and-coversnothing-are-used.phpt @@ -0,0 +1,31 @@ +--TEST-- +phpunit ../_files/code-coverage-targeting/CoversClassCoversNothingTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\CoversClassCoversNothingTest::testOne +#[Covers*] and #[Uses*] attributes do not have an effect when the #[CoversNothing] attribute is used + +%sCoversClassCoversNothingTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-covers-and-uses.phpt b/tests/end-to-end/metadata/warning-covers-and-uses.phpt new file mode 100644 index 00000000000..3b79de18a04 --- /dev/null +++ b/tests/end-to-end/metadata/warning-covers-and-uses.phpt @@ -0,0 +1,31 @@ +--TEST-- +phpunit ../_files/code-coverage-targeting/CoversAndUsesTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\CoversAndUsesTest::testOne +Class PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\SomeClass is targeted by both "Covers" and "Uses" attributes + +%sCoversAndUsesTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-duplicate-covers-targets.phpt b/tests/end-to-end/metadata/warning-duplicate-covers-targets.phpt new file mode 100644 index 00000000000..c337b5e514e --- /dev/null +++ b/tests/end-to-end/metadata/warning-duplicate-covers-targets.phpt @@ -0,0 +1,31 @@ +--TEST-- +phpunit ../_files/code-coverage-targeting/DuplicateCoversTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\DuplicateCoversTest::testOne +Class PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\SomeClass is targeted multiple times by the same "Covers" attribute + +%sDuplicateCoversTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-duplicate-uses-targets.phpt b/tests/end-to-end/metadata/warning-duplicate-uses-targets.phpt new file mode 100644 index 00000000000..7806ed001b6 --- /dev/null +++ b/tests/end-to-end/metadata/warning-duplicate-uses-targets.phpt @@ -0,0 +1,31 @@ +--TEST-- +phpunit ../_files/code-coverage-targeting/DuplicateUsesTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\DuplicateUsesTest::testOne +Class PHPUnit\TestFixture\CodeCoverageTargeting\Warnings\SomeClass is targeted multiple times by the same "Uses" attribute + +%sDuplicateUsesTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-large-and-medium-are-used.phpt b/tests/end-to-end/metadata/warning-large-and-medium-are-used.phpt new file mode 100644 index 00000000000..5bb9c3ad204 --- /dev/null +++ b/tests/end-to-end/metadata/warning-large-and-medium-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/LargeMediumTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Medium] cannot be combined with #[Small] or #[Large] for class PHPUnit\TestFixture\SizeCombinations\LargeMediumTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-large-and-small-are-used.phpt b/tests/end-to-end/metadata/warning-large-and-small-are-used.phpt new file mode 100644 index 00000000000..4cbcad68446 --- /dev/null +++ b/tests/end-to-end/metadata/warning-large-and-small-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/LargeSmallTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Small] cannot be combined with #[Medium] or #[Large] for class PHPUnit\TestFixture\SizeCombinations\LargeSmallTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-medium-and-large-are-used.phpt b/tests/end-to-end/metadata/warning-medium-and-large-are-used.phpt new file mode 100644 index 00000000000..d6918e5dd9a --- /dev/null +++ b/tests/end-to-end/metadata/warning-medium-and-large-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/MediumLargeTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Large] cannot be combined with #[Small] or #[Medium] for class PHPUnit\TestFixture\SizeCombinations\MediumLargeTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-medium-and-small-are-used.phpt b/tests/end-to-end/metadata/warning-medium-and-small-are-used.phpt new file mode 100644 index 00000000000..a01d41928ca --- /dev/null +++ b/tests/end-to-end/metadata/warning-medium-and-small-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/MediumSmallTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Small] cannot be combined with #[Medium] or #[Large] for class PHPUnit\TestFixture\SizeCombinations\MediumSmallTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-json-types.phpt b/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-json-types.phpt new file mode 100644 index 00000000000..65ed846b405 --- /dev/null +++ b/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-json-types.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit ../_files/TestWithJsonAttributeAndDataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\TestWithJsonAttributeAndDataProviderTest::testWithDifferentProviderTypes +Mixing #[DataProvider*] and #[TestWith*] attributes is not supported, only the data provided by #[DataProvider*] will be used + +%sTestWithJsonAttributeAndDataProviderTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-types.phpt b/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-types.phpt new file mode 100644 index 00000000000..cd4f1985284 --- /dev/null +++ b/tests/end-to-end/metadata/warning-mix-dataprovider-test-with-types.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit ../_files/TestWithAttributeAndDataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\TestWithAttributeAndDataProviderTest::testWithDifferentProviderTypes +Mixing #[DataProvider*] and #[TestWith*] attributes is not supported, only the data provided by #[DataProvider*] will be used + +%sTestWithAttributeAndDataProviderTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-mix-external-dataprovider-with-types.phpt b/tests/end-to-end/metadata/warning-mix-external-dataprovider-with-types.phpt new file mode 100644 index 00000000000..5c30e91da7d --- /dev/null +++ b/tests/end-to-end/metadata/warning-mix-external-dataprovider-with-types.phpt @@ -0,0 +1,29 @@ +--TEST-- +phpunit ../_files/TestWithAttributeAndExternalDataProviderTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\TestWithAttributeAndExternalDataProviderTest::testWithDifferentProviderTypes +Mixing #[DataProvider*] and #[TestWith*] attributes is not supported, only the data provided by #[DataProvider*] will be used + +%sTestWithAttributeAndExternalDataProviderTest.php:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-size-is-used-as-group-name.phpt b/tests/end-to-end/metadata/warning-size-is-used-as-group-name.phpt new file mode 100644 index 00000000000..9e65bbd802c --- /dev/null +++ b/tests/end-to-end/metadata/warning-size-is-used-as-group-name.phpt @@ -0,0 +1,36 @@ +--TEST-- +phpunit ../_files/size-groups/SizeGroupsTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +There were 6 PHPUnit test runner warnings: + +1) Group name "small" is not allowed for class PHPUnit\TestFixture\SizeGroups\ClassLevelTest + +2) Group name "medium" is not allowed for class PHPUnit\TestFixture\SizeGroups\ClassLevelTest + +3) Group name "large" is not allowed for class PHPUnit\TestFixture\SizeGroups\ClassLevelTest + +4) Group name "small" is not allowed for method PHPUnit\TestFixture\SizeGroups\MethodLevelTest::testOne + +5) Group name "medium" is not allowed for method PHPUnit\TestFixture\SizeGroups\MethodLevelTest::testOne + +6) Group name "large" is not allowed for method PHPUnit\TestFixture\SizeGroups\MethodLevelTest::testOne + +OK, but there were issues! +Tests: 2, Assertions: 2, PHPUnit Warnings: 6. diff --git a/tests/end-to-end/metadata/warning-small-and-large-are-used.phpt b/tests/end-to-end/metadata/warning-small-and-large-are-used.phpt new file mode 100644 index 00000000000..c4278c936a5 --- /dev/null +++ b/tests/end-to-end/metadata/warning-small-and-large-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/SmallLargeTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Large] cannot be combined with #[Small] or #[Medium] for class PHPUnit\TestFixture\SizeCombinations\SmallLargeTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-small-and-medium-are-used.phpt b/tests/end-to-end/metadata/warning-small-and-medium-are-used.phpt new file mode 100644 index 00000000000..5031346acc2 --- /dev/null +++ b/tests/end-to-end/metadata/warning-small-and-medium-are-used.phpt @@ -0,0 +1,26 @@ +--TEST-- +phpunit ../_files/size-combinations/SmallMediumTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) #[Medium] cannot be combined with #[Small] or #[Large] for class PHPUnit\TestFixture\SizeCombinations\SmallMediumTest + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/metadata/warning-test-attribute-on-hook-methods.phpt b/tests/end-to-end/metadata/warning-test-attribute-on-hook-methods.phpt new file mode 100644 index 00000000000..310e5e7d430 --- /dev/null +++ b/tests/end-to-end/metadata/warning-test-attribute-on-hook-methods.phpt @@ -0,0 +1,48 @@ +--TEST-- +phpunit ../_files/size-combinations/SmallMediumTest.php +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There were 12 PHPUnit test runner warnings: + +1) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::before_class() cannot be used both as a hook method and as a test method + +2) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::after_class() cannot be used both as a hook method and as a test method + +3) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::setUpBeforeClass() cannot be used both as a hook method and as a test method + +4) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::tearDownAfterClass() cannot be used both as a hook method and as a test method + +5) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::setUp() cannot be used both as a hook method and as a test method + +6) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::assertPreConditions() cannot be used both as a hook method and as a test method + +7) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::assertPostConditions() cannot be used both as a hook method and as a test method + +8) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::tearDown() cannot be used both as a hook method and as a test method + +9) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::before_method() cannot be used both as a hook method and as a test method + +10) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::pre_condition() cannot be used both as a hook method and as a test method + +11) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::post_condition() cannot be used both as a hook method and as a test method + +12) Method PHPUnit\TestFixture\AttributesOnTemplateMethods\TestAttributeOnHookMethodsTest::after_method() cannot be used both as a hook method and as a test method + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 12. diff --git a/tests/end-to-end/metadata/with-environment-variable.phpt b/tests/end-to-end/metadata/with-environment-variable.phpt new file mode 100644 index 00000000000..355d11ff44a --- /dev/null +++ b/tests/end-to-end/metadata/with-environment-variable.phpt @@ -0,0 +1,24 @@ +--TEST-- +Tests are correctly ran based on environment variables requirements +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +............... 15 / 15 (100%) + +Time: %s, Memory: %s + +OK (15 tests, 42 assertions) + diff --git a/tests/end-to-end/migration/_files/migration-from-100/phpunit-10.0.xml b/tests/end-to-end/migration/_files/migration-from-100/phpunit-10.0.xml new file mode 100644 index 00000000000..9967d0551ea --- /dev/null +++ b/tests/end-to-end/migration/_files/migration-from-100/phpunit-10.0.xml @@ -0,0 +1,17 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/migration/_files/migration-from-110/phpunit-11.0.xml b/tests/end-to-end/migration/_files/migration-from-110/phpunit-11.0.xml new file mode 100644 index 00000000000..684b3b9159d --- /dev/null +++ b/tests/end-to-end/migration/_files/migration-from-110/phpunit-11.0.xml @@ -0,0 +1,12 @@ + + + + + tests + + + + + diff --git a/tests/end-to-end/migration/_files/migration-from-85/phpunit-8.5.xml b/tests/end-to-end/migration/_files/migration-from-85/phpunit-8.5.xml new file mode 100644 index 00000000000..f2367d7eabb --- /dev/null +++ b/tests/end-to-end/migration/_files/migration-from-85/phpunit-8.5.xml @@ -0,0 +1,22 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/migration/_files/migration-from-92/phpunit-9.2.xml b/tests/end-to-end/migration/_files/migration-from-92/phpunit-9.2.xml new file mode 100644 index 00000000000..40fcead786c --- /dev/null +++ b/tests/end-to-end/migration/_files/migration-from-92/phpunit-9.2.xml @@ -0,0 +1,23 @@ + + + + + tests + + + + + + src + file.php + + + diff --git a/tests/end-to-end/migration/_files/migration-from-95/phpunit-9.5.xml b/tests/end-to-end/migration/_files/migration-from-95/phpunit-9.5.xml new file mode 100644 index 00000000000..f34a36108b8 --- /dev/null +++ b/tests/end-to-end/migration/_files/migration-from-95/phpunit-9.5.xml @@ -0,0 +1,41 @@ + + + + + tests + + + + + + src + + + + + + + diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/phpunit.xml b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/phpunit.xml new file mode 100644 index 00000000000..9c00f88e05c --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/src/Greeter.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/src/Greeter.php new file mode 100644 index 00000000000..8032685fa53 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/tests/GreeterTest.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/tests/GreeterTest.php new file mode 100644 index 00000000000..65f3dfd1d9e --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-100-is-detected/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Greeter::class)] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/phpunit.xml b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/phpunit.xml new file mode 100644 index 00000000000..f2367d7eabb --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/phpunit.xml @@ -0,0 +1,22 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/src/Greeter.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/src/Greeter.php new file mode 100644 index 00000000000..8032685fa53 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/tests/GreeterTest.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/tests/GreeterTest.php new file mode 100644 index 00000000000..65f3dfd1d9e --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-85-is-detected/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Greeter::class)] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/phpunit.xml b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/phpunit.xml new file mode 100644 index 00000000000..b855a43ff25 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/phpunit.xml @@ -0,0 +1,22 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/src/Greeter.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/src/Greeter.php new file mode 100644 index 00000000000..8032685fa53 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/tests/GreeterTest.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/tests/GreeterTest.php new file mode 100644 index 00000000000..65f3dfd1d9e --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Greeter::class)] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/phpunit.xml b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/phpunit.xml new file mode 100644 index 00000000000..f34a36108b8 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/phpunit.xml @@ -0,0 +1,41 @@ + + + + + tests + + + + + + src + + + + + + + diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/src/Greeter.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/src/Greeter.php new file mode 100644 index 00000000000..8032685fa53 --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/tests/GreeterTest.php b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/tests/GreeterTest.php new file mode 100644 index 00000000000..65f3dfd1d9e --- /dev/null +++ b/tests/end-to-end/migration/_files/possibility-to-migrate-from-95-is-detected/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Migration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Greeter::class)] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/migration/_files/unsupported-schema/phpunit.xml b/tests/end-to-end/migration/_files/unsupported-schema/phpunit.xml new file mode 100644 index 00000000000..b24baa02e01 --- /dev/null +++ b/tests/end-to-end/migration/_files/unsupported-schema/phpunit.xml @@ -0,0 +1,6 @@ + + + bar + diff --git a/tests/end-to-end/migration/migration-from-100.phpt b/tests/end-to-end/migration/migration-from-100.phpt new file mode 100644 index 00000000000..edd9aed6c82 --- /dev/null +++ b/tests/end-to-end/migration/migration-from-100.phpt @@ -0,0 +1,22 @@ +--TEST-- +Configuration migration from PHPUnit 10.0 format works +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %sphpunit.xml.bak +Migrated configuration: %sphpunit.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %sphpunit.xml.bak +Migrated configuration: %sphpunit.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %scustom.xml.bak +Migrated configuration: %scustom.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %sphpunit.xml.bak +Migrated configuration: %sphpunit.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %sphpunit.xml.bak +Migrated configuration: %sphpunit.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Created backup: %sphpunit.xml.bak +Migrated configuration: %sphpunit.xml +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s +Configuration: %sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner deprecation: + +1) Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/migration/possibility-to-migrate-from-85-is-detected.phpt b/tests/end-to-end/migration/possibility-to-migrate-from-85-is-detected.phpt new file mode 100644 index 00000000000..e089167a5db --- /dev/null +++ b/tests/end-to-end/migration/possibility-to-migrate-from-85-is-detected.phpt @@ -0,0 +1,28 @@ +--TEST-- +Possibility to migrate XML configuration file from PHPUnit 8.5 format is detected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s +Configuration: %sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner deprecation: + +1) Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/migration/possibility-to-migrate-from-92-is-detected.phpt b/tests/end-to-end/migration/possibility-to-migrate-from-92-is-detected.phpt new file mode 100644 index 00000000000..b1ffbfca961 --- /dev/null +++ b/tests/end-to-end/migration/possibility-to-migrate-from-92-is-detected.phpt @@ -0,0 +1,28 @@ +--TEST-- +Possibility to migrate XML configuration file from PHPUnit 9.2 format is detected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s +Configuration: %sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner deprecation: + +1) Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/migration/possibility-to-migrate-from-95-is-detected.phpt b/tests/end-to-end/migration/possibility-to-migrate-from-95-is-detected.phpt new file mode 100644 index 00000000000..68956d8bcb3 --- /dev/null +++ b/tests/end-to-end/migration/possibility-to-migrate-from-95-is-detected.phpt @@ -0,0 +1,28 @@ +--TEST-- +Possibility to migrate XML configuration file from PHPUnit 9.5 format is detected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: PHP %s +Configuration: %sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner deprecation: + +1) Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/migration/unsupported-schema.phpt b/tests/end-to-end/migration/unsupported-schema.phpt new file mode 100644 index 00000000000..60186771dec --- /dev/null +++ b/tests/end-to-end/migration/unsupported-schema.phpt @@ -0,0 +1,22 @@ +--TEST-- +Configuration migration is not possible when the configuration file does not validate against any known schema +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Migration of %s failed: +The file does not validate against any known schema +--CLEAN-- +hi(); + } +} + +class Foo +{ + use ChildTrait; + + public function speak() + { + return $this->world(); + } +} + +require_once __DIR__ . '/../../../bootstrap.php'; + +$generator = new \PHPUnit\Framework\MockObject\Generator\Generator; + +$mock = $generator->generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function speak() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'speak', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/3154_namespaced_constant_resolving.phpt b/tests/end-to-end/mock-objects/generator/3154_namespaced_constant_resolving.phpt new file mode 100644 index 00000000000..b965f871e20 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/3154_namespaced_constant_resolving.phpt @@ -0,0 +1,84 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit-mock-objects/issues/420 +https://github.com/sebastianbergmann/phpunit/issues/3154 +--FILE-- + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +const A_CONSTANT = 17; +const PHP_VERSION = ""; + +class Issue3154 +{ + public function a(int $i = PHP_INT_MAX, int $j = A_CONSTANT, string $v = \PHP_VERSION, string $z = '#'): string + { + return $z."sum: ".($i+$j).$v; + } +} +require_once __DIR__ . '/../../../bootstrap.php'; + +$generator = new \PHPUnit\Framework\MockObject\Generator\Generator; + +$mock = $generator->generate( + type: Issue3154::class, + mockObject: true, + methods: [], + mockClassName: 'Issue3154Mock', +); + +print $mock->classCode(); +--EXPECTF-- +declare(strict_types=1); + +class Issue3154Mock extends Is\Namespaced\Issue3154 implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function a(int $i = %d, int $j = 17, string $v = '%s', string $z = '#'): string + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$i, $j, $v, $z]; + $__phpunit_count = func_num_args(); + + if (4 !== null && $__phpunit_count > 4) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 4; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Is\Namespaced\Issue3154', 'a', $__phpunit_arguments, 'string', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/3967.phpt b/tests/end-to-end/mock-objects/generator/3967.phpt new file mode 100644 index 00000000000..e7fb931a981 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/3967.phpt @@ -0,0 +1,72 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/3967 +--FILE-- +generate( + type: 'Baz', + mockObject: true, + methods: [], + mockClassName: 'MockBaz', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockBaz extends Exception implements Baz, PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\ProxiedCloneMethod; + + public function foo(): string + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Bar', 'foo', $__phpunit_arguments, 'string', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/397.phpt b/tests/end-to-end/mock-objects/generator/397.phpt new file mode 100644 index 00000000000..321fcc7ceaa --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/397.phpt @@ -0,0 +1,70 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit-mock-objects/issues/397 +--FILE-- +generate( + type: C::class, + mockObject: true, + methods: [], + mockClassName: 'MockC', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockC extends C implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function m(?C $other): C + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$other]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'C', 'm', $__phpunit_arguments, 'C', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/4139.phpt b/tests/end-to-end/mock-objects/generator/4139.phpt new file mode 100644 index 00000000000..50309c50b35 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/4139.phpt @@ -0,0 +1,65 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4139 +--FILE-- +generate( + type: InterfaceWithConstructor::class, + mockObject: true, +); + +print $mock->classCode(); +--EXPECTF-- +declare(strict_types=1); + +class %s implements PHPUnit\Framework\MockObject\MockObjectInternal, InterfaceWithConstructor +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function __construct() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'InterfaceWithConstructor', '__construct', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/abstract_class.phpt b/tests/end-to-end/mock-objects/generator/abstract_class.phpt new file mode 100644 index 00000000000..de69f4bee64 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/abstract_class.phpt @@ -0,0 +1,148 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function one() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'one', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } + + public function two() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'two', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } + + protected function three() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'three', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class.phpt b/tests/end-to-end/mock-objects/generator/class.phpt new file mode 100644 index 00000000000..77470588c31 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class.phpt @@ -0,0 +1,111 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } + + public function baz(Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'baz', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_call_parent_clone.phpt b/tests/end-to-end/mock-objects/generator/class_call_parent_clone.phpt new file mode 100644 index 00000000000..a4fdcab1835 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_call_parent_clone.phpt @@ -0,0 +1,33 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\ProxiedCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/class_call_parent_constructor.phpt new file mode 100644 index 00000000000..1558555b381 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_call_parent_constructor.phpt @@ -0,0 +1,33 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_dont_call_parent_clone.phpt b/tests/end-to-end/mock-objects/generator/class_dont_call_parent_clone.phpt new file mode 100644 index 00000000000..805288c37eb --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_dont_call_parent_clone.phpt @@ -0,0 +1,34 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', false) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', + callOriginalClone: false +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_dont_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/class_dont_call_parent_constructor.phpt new file mode 100644 index 00000000000..1558555b381 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_dont_call_parent_constructor.phpt @@ -0,0 +1,33 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_implementing_interface_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/class_implementing_interface_call_parent_constructor.phpt new file mode 100644 index 00000000000..6c1ff3accd8 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_implementing_interface_call_parent_constructor.phpt @@ -0,0 +1,38 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_implementing_interface_dont_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/class_implementing_interface_dont_call_parent_constructor.phpt new file mode 100644 index 00000000000..6c1ff3accd8 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_implementing_interface_dont_call_parent_constructor.phpt @@ -0,0 +1,38 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_nonexistent_method.phpt b/tests/end-to-end/mock-objects/generator/class_nonexistent_method.phpt new file mode 100644 index 00000000000..8d5df73f928 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_nonexistent_method.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', array('bar'), 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: ['bar'], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_partial.phpt b/tests/end-to-end/mock-objects/generator/class_partial.phpt new file mode 100644 index 00000000000..2fa52500c34 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_partial.phpt @@ -0,0 +1,74 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', array('bar'), 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: ['bar'], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_with_deprecated_method.phpt b/tests/end-to-end/mock-objects/generator/class_with_deprecated_method.phpt new file mode 100644 index 00000000000..3506ad581f4 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_with_deprecated_method.phpt @@ -0,0 +1,76 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('ClassWithDeprecatedMethod', [], 'MockFoo', TRUE, TRUE) +--FILE-- +generate( + type: 'ClassWithDeprecatedMethod', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends ClassWithDeprecatedMethod implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function deprecatedMethod() + { + @trigger_error('The ClassWithDeprecatedMethod::deprecatedMethod method is deprecated (this method is deprecated).', E_USER_DEPRECATED); + + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithDeprecatedMethod', 'deprecatedMethod', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_with_final_method.phpt b/tests/end-to-end/mock-objects/generator/class_with_final_method.phpt new file mode 100644 index 00000000000..d68911c1451 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_with_final_method.phpt @@ -0,0 +1,33 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('ClassWithFinalMethod', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'ClassWithFinalMethod', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends ClassWithFinalMethod implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/class_with_method_with_nullable_typehinted_variadic_arguments.phpt b/tests/end-to-end/mock-objects/generator/class_with_method_with_nullable_typehinted_variadic_arguments.phpt new file mode 100644 index 00000000000..67947213d74 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_with_method_with_nullable_typehinted_variadic_arguments.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('ClassWithMethodWithVariadicArguments', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'ClassWithMethodWithNullableTypehintedVariadicArguments', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends ClassWithMethodWithNullableTypehintedVariadicArguments implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function methodWithNullableTypehintedVariadicArguments($a, ?string ...$parameters) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$a]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithMethodWithNullableTypehintedVariadicArguments', 'methodWithNullableTypehintedVariadicArguments', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_with_method_with_typehinted_variadic_arguments.phpt b/tests/end-to-end/mock-objects/generator/class_with_method_with_typehinted_variadic_arguments.phpt new file mode 100644 index 00000000000..9c264fb08df --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_with_method_with_typehinted_variadic_arguments.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('ClassWithMethodWithVariadicArguments', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'ClassWithMethodWithTypehintedVariadicArguments', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends ClassWithMethodWithTypehintedVariadicArguments implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function methodWithTypehintedVariadicArguments($a, string ...$parameters) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$a]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithMethodWithTypehintedVariadicArguments', 'methodWithTypehintedVariadicArguments', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/class_with_method_with_variadic_arguments.phpt b/tests/end-to-end/mock-objects/generator/class_with_method_with_variadic_arguments.phpt new file mode 100644 index 00000000000..1f74bafda4b --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/class_with_method_with_variadic_arguments.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('ClassWithMethodWithVariadicArguments', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'ClassWithMethodWithVariadicArguments', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends ClassWithMethodWithVariadicArguments implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function methodWithVariadicArguments($a, ...$parameters) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$a]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithMethodWithVariadicArguments', 'methodWithVariadicArguments', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/constant_as_parameter_default_value.phpt b/tests/end-to-end/mock-objects/generator/constant_as_parameter_default_value.phpt new file mode 100644 index 00000000000..89a5b0079a1 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/constant_as_parameter_default_value.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECTF-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(int $baz = %d) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/extendable_class_with_final_property.phpt b/tests/end-to-end/mock-objects/generator/extendable_class_with_final_property.phpt new file mode 100644 index 00000000000..9a5ba4d1941 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/extendable_class_with_final_property.phpt @@ -0,0 +1,39 @@ +--TEST-- +Extendable class with property with final property +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo extends Foo implements PHPUnit\Framework\MockObject\StubInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_final_get_hook.phpt b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_final_get_hook.phpt new file mode 100644 index 00000000000..753c04237d4 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_final_get_hook.phpt @@ -0,0 +1,39 @@ +--TEST-- +Extendable class with property with final get property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo extends Foo implements PHPUnit\Framework\MockObject\StubInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_and_set_hooks.phpt b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_and_set_hooks.phpt new file mode 100644 index 00000000000..18de0cdb2da --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_and_set_hooks.phpt @@ -0,0 +1,61 @@ +--TEST-- +Extendable class with property with non-final get and set property hooks +--SKIPIF-- +bar = $value; + } + } +} + +require_once __DIR__ . '/../../../bootstrap.php'; + +$generator = new \PHPUnit\Framework\MockObject\Generator\Generator; + +$testDoubleClass = $generator->generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo extends Foo implements PHPUnit\Framework\MockObject\StubInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::get', [], 'string', $this + ) + ); + } + + set (string $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::set', [$value], 'void', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_hook.phpt b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_hook.phpt new file mode 100644 index 00000000000..1108a49905d --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_get_hook.phpt @@ -0,0 +1,49 @@ +--TEST-- +Extendable class with property with non-final get property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo extends Foo implements PHPUnit\Framework\MockObject\StubInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::get', [], 'string', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_set_hook.phpt b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_set_hook.phpt new file mode 100644 index 00000000000..df0c7ba0c60 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/extendable_class_with_property_with_set_hook.phpt @@ -0,0 +1,49 @@ +--TEST-- +Extendable class with property with non-final set property hook +--SKIPIF-- +bar = $value; + } + } +} + +require_once __DIR__ . '/../../../bootstrap.php'; + +$generator = new \PHPUnit\Framework\MockObject\Generator\Generator; + +$testDoubleClass = $generator->generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo extends Foo implements PHPUnit\Framework\MockObject\StubInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + set (string $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::set', [$value], 'void', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface.phpt b/tests/end-to-end/mock-objects/generator/interface.phpt new file mode 100644 index 00000000000..540b502757c --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_get_hook.phpt b/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_get_hook.phpt new file mode 100644 index 00000000000..5ee090dd1ba --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_get_hook.phpt @@ -0,0 +1,45 @@ +--TEST-- +Interface with nullable property with get property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo implements PHPUnit\Framework\MockObject\StubInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public ?string $bar { + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::get', [], '?string', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_set_hook.phpt b/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_set_hook.phpt new file mode 100644 index 00000000000..a0be2b822a2 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface_with_nullable_property_with_set_hook.phpt @@ -0,0 +1,45 @@ +--TEST-- +Interface with nullable property with set property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo implements PHPUnit\Framework\MockObject\StubInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public ?string $bar { + set (?string $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::set', [$value], 'void', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_and_set_hooks.phpt b/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_and_set_hooks.phpt new file mode 100644 index 00000000000..cf61e81f91e --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_and_set_hooks.phpt @@ -0,0 +1,53 @@ +--TEST-- +Interface with property with get and set property hooks +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo implements PHPUnit\Framework\MockObject\StubInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::get', [], 'string', $this + ) + ); + } + + set (string $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::set', [$value], 'void', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_hook.phpt b/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_hook.phpt new file mode 100644 index 00000000000..442393e34fe --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface_with_property_with_get_hook.phpt @@ -0,0 +1,45 @@ +--TEST-- +Interface with property with get property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo implements PHPUnit\Framework\MockObject\StubInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + get { + return $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::get', [], 'string', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/interface_with_property_with_set_hook.phpt b/tests/end-to-end/mock-objects/generator/interface_with_property_with_set_hook.phpt new file mode 100644 index 00000000000..5502369225b --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/interface_with_property_with_set_hook.phpt @@ -0,0 +1,45 @@ +--TEST-- +Interface with property with set property hook +--SKIPIF-- +generate( + type: Foo::class, + mockObject: false, + methods: [], + mockClassName: 'TestStubFoo', +); + +print $testDoubleClass->classCode(); +--EXPECT-- +declare(strict_types=1); + +class TestStubFoo implements PHPUnit\Framework\MockObject\StubInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public string $bar { + set (string $value) { + $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'TestStubFoo', '$bar::set', [$value], 'void', $this + ) + ); + } + } +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class.phpt new file mode 100644 index 00000000000..75d013545ba --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class.phpt @@ -0,0 +1,113 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(NS\Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'NS\Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } + + public function baz(NS\Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'NS\Foo', 'baz', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_clone.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_clone.phpt new file mode 100644 index 00000000000..ec75e561f28 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_clone.phpt @@ -0,0 +1,35 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\ProxiedCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_constructor.phpt new file mode 100644 index 00000000000..4af90495f11 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_call_parent_constructor.phpt @@ -0,0 +1,35 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_clone.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_clone.phpt new file mode 100644 index 00000000000..6fd9e032a9e --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_clone.phpt @@ -0,0 +1,36 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', false) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', + callOriginalClone: false, +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_constructor.phpt new file mode 100644 index 00000000000..4af90495f11 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_dont_call_parent_constructor.phpt @@ -0,0 +1,35 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_call_parent_constructor.phpt new file mode 100644 index 00000000000..322732cff74 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_call_parent_constructor.phpt @@ -0,0 +1,40 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_dont_call_parent_constructor.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_dont_call_parent_constructor.phpt new file mode 100644 index 00000000000..322732cff74 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_implementing_interface_dont_call_parent_constructor.phpt @@ -0,0 +1,40 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_class_partial.phpt b/tests/end-to-end/mock-objects/generator/namespaced_class_partial.phpt new file mode 100644 index 00000000000..503117b634e --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_class_partial.phpt @@ -0,0 +1,76 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', array('bar'), 'MockFoo', true, true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: ['bar'], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends NS\Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(NS\Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'NS\Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/namespaced_interface.phpt b/tests/end-to-end/mock-objects/generator/namespaced_interface.phpt new file mode 100644 index 00000000000..e204034f8c9 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/namespaced_interface.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('NS\Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'NS\Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, NS\Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(NS\Foo $foo) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'NS\Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/nullable_types.phpt b/tests/end-to-end/mock-objects/generator/nullable_types.phpt new file mode 100644 index 00000000000..168886b527c --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/nullable_types.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(?int $x) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$x]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/nullable_union_type_parameter.phpt b/tests/end-to-end/mock-objects/generator/nullable_union_type_parameter.phpt new file mode 100644 index 00000000000..5ff35f55b17 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/nullable_union_type_parameter.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(bool|int $baz, Foo|null|stdClass $other) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz, $other]; + $__phpunit_count = func_num_args(); + + if (2 !== null && $__phpunit_count > 2) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 2; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/nullable_union_type_return.phpt b/tests/end-to-end/mock-objects/generator/nullable_union_type_return.phpt new file mode 100644 index 00000000000..35db70f87a5 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/nullable_union_type_return.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): bool|int|null + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'bool|int|null', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_dnf.phpt b/tests/end-to-end/mock-objects/generator/parameter_dnf.phpt new file mode 100644 index 00000000000..6d3c2aab50b --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_dnf.phpt @@ -0,0 +1,78 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar((A&B)|int|null $baz) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_false.phpt b/tests/end-to-end/mock-objects/generator/parameter_false.phpt new file mode 100644 index 00000000000..356451aaeef --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_false.phpt @@ -0,0 +1,66 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(false $baz): void + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'void', $this + ) + ); + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_intersection.phpt b/tests/end-to-end/mock-objects/generator/parameter_intersection.phpt new file mode 100644 index 00000000000..e30514eff55 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_intersection.phpt @@ -0,0 +1,78 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(AnInterface&AnotherInterface $baz) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_null.phpt b/tests/end-to-end/mock-objects/generator/parameter_null.phpt new file mode 100644 index 00000000000..8c091b99f06 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_null.phpt @@ -0,0 +1,66 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(null $baz): void + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'void', $this + ) + ); + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_true.phpt b/tests/end-to-end/mock-objects/generator/parameter_true.phpt new file mode 100644 index 00000000000..8f1f8b85c67 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_true.phpt @@ -0,0 +1,66 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(true $baz): void + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'void', $this + ) + ); + } +} diff --git a/tests/end-to-end/mock-objects/generator/parameter_union.phpt b/tests/end-to-end/mock-objects/generator/parameter_union.phpt new file mode 100644 index 00000000000..2d1007bb48d --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/parameter_union.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(bool|int $baz, Foo|stdClass $other) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz, $other]; + $__phpunit_count = func_num_args(); + + if (2 !== null && $__phpunit_count > 2) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 2; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_closure.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_closure.phpt new file mode 100644 index 00000000000..70a39582f42 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_closure.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): Closure + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Closure', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_dnf.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_dnf.phpt new file mode 100644 index 00000000000..c1b3e2cbac9 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_dnf.phpt @@ -0,0 +1,78 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): (A&B)|int|null + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '(A&B)|int|null', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_false.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_false.phpt new file mode 100644 index 00000000000..4ee84e1b33e --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_false.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): false + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'false', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_final.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_final.phpt new file mode 100644 index 00000000000..40af8ddc812 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_final.phpt @@ -0,0 +1,75 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): FinalClass + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'FinalClass', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_generator.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_generator.phpt new file mode 100644 index 00000000000..227d95a419e --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_generator.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): Generator + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Generator', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_generator_empty_by_default.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_generator_empty_by_default.phpt new file mode 100644 index 00000000000..5797c8711a0 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_generator_empty_by_default.phpt @@ -0,0 +1,34 @@ +--TEST-- +Iterable return types should return empty array by default +--SKIPIF-- +testDouble( + type: 'Foo', + mockObject: false, +); + +var_dump(iterator_to_array($mock->forTraversable())); +var_dump(iterator_to_array($mock->forGenerator())); +var_dump(iterator_to_array($mock->forIterable())); +--EXPECT-- +array(0) { +} +array(0) { +} +array(0) { +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_intersection.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_intersection.phpt new file mode 100644 index 00000000000..f4695d45944 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_intersection.phpt @@ -0,0 +1,78 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): AnInterface&AnotherInterface + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'AnInterface&AnotherInterface', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_never.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_never.phpt new file mode 100644 index 00000000000..5d2512f9f8d --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_never.phpt @@ -0,0 +1,66 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz): never + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'never', $this + ) + ); + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_null.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_null.phpt new file mode 100644 index 00000000000..f783b4da419 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_null.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): null + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'null', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_nullable.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_nullable.phpt new file mode 100644 index 00000000000..c6b2d15c63b --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_nullable.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz): ?string + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '?string', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_object_method.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_object_method.phpt new file mode 100644 index 00000000000..12e368abbe7 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_object_method.phpt @@ -0,0 +1,71 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz): Bar + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Bar', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_parent.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_parent.phpt new file mode 100644 index 00000000000..35f8cfc00af --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_parent.phpt @@ -0,0 +1,75 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Bar', [], 'MockBar', true, true) +--FILE-- +generate( + type: 'Bar', + mockObject: true, + methods: [], + mockClassName: 'MockBar', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockBar extends Bar implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function baz(): Foo + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Bar', 'baz', $__phpunit_arguments, 'Foo', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_self.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_self.phpt new file mode 100644 index 00000000000..53263bb948f --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_self.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz): Foo + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Foo', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_static.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_static.phpt new file mode 100644 index 00000000000..e817c58445f --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_static.phpt @@ -0,0 +1,152 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'ClassWithStaticReturnTypes', + mockObject: true, + methods: [], + mockClassName: 'MockClassWithStaticReturnTypes', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockClassWithStaticReturnTypes extends ClassWithStaticReturnTypes implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function returnsStatic(): static + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithStaticReturnTypes', 'returnsStatic', $__phpunit_arguments, 'static', $this + ) + ); + + return $__phpunit_result; + } + + public function returnsStaticOrNull(): ?static + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithStaticReturnTypes', 'returnsStaticOrNull', $__phpunit_arguments, '?static', $this + ) + ); + + return $__phpunit_result; + } + + public function returnsUnionWithStatic(): static|stdClass + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'ClassWithStaticReturnTypes', 'returnsUnionWithStatic', $__phpunit_arguments, 'static|stdClass', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_static_method.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_static_method.phpt new file mode 100644 index 00000000000..cc4beeeadf2 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_static_method.phpt @@ -0,0 +1,39 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public static function bar(string $baz): Bar + { + throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "bar" cannot be invoked on mock object'); + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_true.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_true.phpt new file mode 100644 index 00000000000..aca19906fee --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_true.phpt @@ -0,0 +1,68 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): true + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'true', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_union.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_union.phpt new file mode 100644 index 00000000000..ed575f56c85 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_union.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: Foo::class, + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(): bool|int + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'bool|int', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/generator/return_type_declarations_void.phpt b/tests/end-to-end/mock-objects/generator/return_type_declarations_void.phpt new file mode 100644 index 00000000000..cf007f95a16 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/return_type_declarations_void.phpt @@ -0,0 +1,66 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo implements PHPUnit\Framework\MockObject\MockObjectInternal, Foo +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz): void + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'void', $this + ) + ); + } +} diff --git a/tests/end-to-end/mock-objects/generator/scalar_type_declarations.phpt b/tests/end-to-end/mock-objects/generator/scalar_type_declarations.phpt new file mode 100644 index 00000000000..b3203db2ea9 --- /dev/null +++ b/tests/end-to-end/mock-objects/generator/scalar_type_declarations.phpt @@ -0,0 +1,70 @@ +--TEST-- +\PHPUnit\Framework\MockObject\Generator\Generator::generate('Foo', [], 'MockFoo', true, true) +--FILE-- +generate( + type: 'Foo', + mockObject: true, + methods: [], + mockClassName: 'MockFoo', +); + +print $mock->classCode(); +--EXPECT-- +declare(strict_types=1); + +class MockFoo extends Foo implements PHPUnit\Framework\MockObject\MockObjectInternal +{ + use PHPUnit\Framework\MockObject\StubApi; + use PHPUnit\Framework\MockObject\MockObjectApi; + use PHPUnit\Framework\MockObject\Method; + use PHPUnit\Framework\MockObject\DoubledCloneMethod; + + public function bar(string $baz) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$baz]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } +} diff --git a/tests/end-to-end/mock-objects/mock-method/deprecated_with_description.phpt b/tests/end-to-end/mock-objects/mock-method/deprecated_with_description.phpt new file mode 100644 index 00000000000..f74e48c11d5 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/deprecated_with_description.phpt @@ -0,0 +1,64 @@ +--TEST-- +Emit deprecation notice when mocking deprecated message. +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public function bar() + { + @trigger_error('The Foo::bar method is deprecated (some explanation).', E_USER_DEPRECATED); + + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/deprecated_without_description.phpt b/tests/end-to-end/mock-objects/mock-method/deprecated_without_description.phpt new file mode 100644 index 00000000000..0b6435cd139 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/deprecated_without_description.phpt @@ -0,0 +1,64 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public function bar() + { + @trigger_error('The Foo::bar method is deprecated ().', E_USER_DEPRECATED); + + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/private_method.phpt b/tests/end-to-end/mock-objects/mock-method/private_method.phpt new file mode 100644 index 00000000000..dd529809c15 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/private_method.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/protected_method.phpt b/tests/end-to-end/mock-objects/mock-method/protected_method.phpt new file mode 100644 index 00000000000..1d60f29750b --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/protected_method.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +protected function bar() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/return_by_reference.phpt b/tests/end-to-end/mock-objects/mock-method/return_by_reference.phpt new file mode 100644 index 00000000000..33da1456e9a --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/return_by_reference.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public function &bar() + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/return_by_reference_with_return_type.phpt b/tests/end-to-end/mock-objects/mock-method/return_by_reference_with_return_type.phpt new file mode 100644 index 00000000000..244af33f2e9 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/return_by_reference_with_return_type.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECTF-- + +public function &bar(): string + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'string', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/return_type.phpt b/tests/end-to-end/mock-objects/mock-method/return_type.phpt new file mode 100644 index 00000000000..b40628173a5 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/return_type.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECTF-- + +public function bar(): string + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'string', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/return_type_parent.phpt b/tests/end-to-end/mock-objects/mock-method/return_type_parent.phpt new file mode 100644 index 00000000000..8538678d3c9 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/return_type_parent.phpt @@ -0,0 +1,63 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECTF-- + +public function bar(): Baz + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Baz', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/return_type_self.phpt b/tests/end-to-end/mock-objects/mock-method/return_type_self.phpt new file mode 100644 index 00000000000..a7661a9cb48 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/return_type_self.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECTF-- + +public function bar(): Foo + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, 'Foo', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/static_method.phpt b/tests/end-to-end/mock-objects/mock-method/static_method.phpt new file mode 100644 index 00000000000..4f975ed29c4 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/static_method.phpt @@ -0,0 +1,27 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public static function bar() + { + throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "bar" cannot be invoked on mock object'); + } diff --git a/tests/end-to-end/mock-objects/mock-method/static_method_with_return_type.phpt b/tests/end-to-end/mock-objects/mock-method/static_method_with_return_type.phpt new file mode 100644 index 00000000000..13f014722e7 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/static_method_with_return_type.phpt @@ -0,0 +1,27 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public static function bar(): bool + { + throw new \PHPUnit\Framework\MockObject\BadMethodCallException('Static method "bar" cannot be invoked on mock object'); + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument.phpt new file mode 100644 index 00000000000..aab00186b9a --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar($arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_default.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_default.phpt new file mode 100644 index 00000000000..46e02d5be56 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_default.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar($arg = false) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_default_constant.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_default_constant.phpt new file mode 100644 index 00000000000..d27fcff2fc2 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_default_constant.phpt @@ -0,0 +1,64 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar($a = 1, $b = 2, $c = 3, $d = 4) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$a, $b, $c, $d]; + $__phpunit_count = func_num_args(); + + if (4 !== null && $__phpunit_count > 4) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 4; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_default_new_expression.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_default_new_expression.phpt new file mode 100644 index 00000000000..1960713225b --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_default_new_expression.phpt @@ -0,0 +1,66 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4929 +--FILE-- +getMethod('method'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +public function method(Foo $foo = new \Foo(1, 2, 3)) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$foo]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Bar', 'method', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_default_null.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_default_null.phpt new file mode 100644 index 00000000000..9c0eeb94f2c --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_default_null.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar($arg = NULL) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_nullable.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_nullable.phpt new file mode 100644 index 00000000000..c06ebd8d363 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_nullable.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(?string $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_reference.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_reference.phpt new file mode 100644 index 00000000000..02d9c799461 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_reference.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(&$arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [&$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_array.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_array.phpt new file mode 100644 index 00000000000..80856caabfa --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_array.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(array $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_callable.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_callable.phpt new file mode 100644 index 00000000000..10422b5fd2f --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_callable.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(callable $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_class.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_class.phpt new file mode 100644 index 00000000000..da6aee4ec22 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_class.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(Exception $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_scalar.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_scalar.phpt new file mode 100644 index 00000000000..eddbac31dd3 --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_scalar.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(string $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_self.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_self.phpt new file mode 100644 index 00000000000..5be3ad94c9a --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_self.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(Foo $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_unkown_class.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_unkown_class.phpt new file mode 100644 index 00000000000..cbbb4720eab --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_unkown_class.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(UnknownClass $arg) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg]; + $__phpunit_count = func_num_args(); + + if (1 !== null && $__phpunit_count > 1) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 1; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_typed_variadic.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_variadic.phpt new file mode 100644 index 00000000000..556bda3a7eb --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_typed_variadic.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(string ...$args) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_argument_variadic.phpt b/tests/end-to-end/mock-objects/mock-method/with_argument_variadic.phpt new file mode 100644 index 00000000000..5cc69f5295d --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_argument_variadic.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar(...$args) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = []; + $__phpunit_count = func_num_args(); + + if (0 !== null && $__phpunit_count > 0) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 0; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/mock-objects/mock-method/with_arguments.phpt b/tests/end-to-end/mock-objects/mock-method/with_arguments.phpt new file mode 100644 index 00000000000..0d3827cfa3e --- /dev/null +++ b/tests/end-to-end/mock-objects/mock-method/with_arguments.phpt @@ -0,0 +1,59 @@ +--TEST-- +Mock static method +--FILE-- +getMethod('bar'), + false, + false +); + +$code = $mockMethod->generateCode(); + +print $code; +--EXPECT-- + +private function bar($arg1, $arg2) + { + $__phpunit_definedVariables = get_defined_vars(); + $__phpunit_namedVariadicParameters = []; + + foreach ($__phpunit_definedVariables as $__phpunit_definedVariableName => $__phpunit_definedVariableValue) { + if ((new ReflectionParameter([__CLASS__, __FUNCTION__], $__phpunit_definedVariableName))->isVariadic()) { + foreach ($__phpunit_definedVariableValue as $__phpunit_key => $__phpunit_namedValue) { + if (is_string($__phpunit_key)) { + $__phpunit_namedVariadicParameters[$__phpunit_key] = $__phpunit_namedValue; + } + } + } + } + + $__phpunit_arguments = [$arg1, $arg2]; + $__phpunit_count = func_num_args(); + + if (2 !== null && $__phpunit_count > 2) { + $__phpunit_arguments_tmp = func_get_args(); + + for ($__phpunit_i = 2; $__phpunit_i < $__phpunit_count; $__phpunit_i++) { + $__phpunit_arguments[] = $__phpunit_arguments_tmp[$__phpunit_i]; + } + } + + $__phpunit_arguments = array_merge($__phpunit_arguments, $__phpunit_namedVariadicParameters); + + $__phpunit_result = $this->__phpunit_getInvocationHandler()->invoke( + new \PHPUnit\Framework\MockObject\Invocation( + 'Foo', 'bar', $__phpunit_arguments, '', $this + ) + ); + + return $__phpunit_result; + } diff --git a/tests/end-to-end/phar/phpunit.xml b/tests/end-to-end/phar/phpunit.xml new file mode 100644 index 00000000000..538ee05c4c0 --- /dev/null +++ b/tests/end-to-end/phar/phpunit.xml @@ -0,0 +1,19 @@ + + + + + tests/standard + tests/phpt + + + + + + src + + + diff --git a/tests/end-to-end/phar/src/Greeter.php b/tests/end-to-end/phar/src/Greeter.php new file mode 100644 index 00000000000..00dc4a68c8c --- /dev/null +++ b/tests/end-to-end/phar/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Phar; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/phar/src/autoload.php b/tests/end-to-end/phar/src/autoload.php new file mode 100644 index 00000000000..c66cf5e50f1 --- /dev/null +++ b/tests/end-to-end/phar/src/autoload.php @@ -0,0 +1,11 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require_once __DIR__ . '/Greeter.php'; diff --git a/tests/end-to-end/phar/tests/phpt/greeter.phpt b/tests/end-to-end/phar/tests/phpt/greeter.phpt new file mode 100644 index 00000000000..04ddbf36925 --- /dev/null +++ b/tests/end-to-end/phar/tests/phpt/greeter.phpt @@ -0,0 +1,11 @@ +--TEST-- +Greeter +--FILE-- +greet(); +--EXPECT-- +Hello world! diff --git a/tests/end-to-end/phar/tests/standard/GreeterTest.php b/tests/end-to-end/phar/tests/standard/GreeterTest.php new file mode 100644 index 00000000000..136d29cd2ba --- /dev/null +++ b/tests/end-to-end/phar/tests/standard/GreeterTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Phar; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Greeter::class)] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } + + #[RunInSeparateProcess] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/4412')] + public function testGreetsInIsolation(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/phar/tests/standard/Issue4399Test.php b/tests/end-to-end/phar/tests/standard/Issue4399Test.php new file mode 100644 index 00000000000..4900d5c2d4d --- /dev/null +++ b/tests/end-to-end/phar/tests/standard/Issue4399Test.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +final class Issue4399Test extends TestCase +{ + public function testOne(): void + { + $this->assertCount(0, []); + } +} diff --git a/tests/end-to-end/phpt/expect-external-location-hint.phpt b/tests/end-to-end/phpt/expect-external-location-hint.phpt new file mode 100644 index 00000000000..8361ab6f90a --- /dev/null +++ b/tests/end-to-end/phpt/expect-external-location-hint.phpt @@ -0,0 +1,39 @@ +--TEST-- +PHPT EXPECT_EXTERNAL results in correct code location hint +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) %stests%eend-to-end%e_files%ephpt-expect-external-location-hint-example.phpt +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'Hello World\n +-This is line two\n +-and this is line three' ++'Hello world\n ++This is line 2\n ++and this is line 3' + +%stests%eend-to-end%e_files%eexpect_external.txt:1 +%stests%eend-to-end%e_files%ephpt-expect-external-location-hint-example.phpt:9 + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/phpt/expect-location-hint.phpt b/tests/end-to-end/phpt/expect-location-hint.phpt new file mode 100644 index 00000000000..a7dee4ce2c9 --- /dev/null +++ b/tests/end-to-end/phpt/expect-location-hint.phpt @@ -0,0 +1,41 @@ +--TEST-- +PHPT EXPECT comparison returns correct code location hint +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) %stests%eend-to-end%e_files%ephpt-expect-location-hint-example.phpt +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'Nothing to see here, move along' ++'Fatal error: Uncaught Error: Call to undefined function some_unknown_function() in %s:2\n ++Stack trace:\n ++#0 {main}\n ++ thrown in %s on line 2' + +%stests%eend-to-end%e_files%ephpt-expect-location-hint-example.phpt:9 + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/phpt/parse-ini-env-section.phpt b/tests/end-to-end/phpt/parse-ini-env-section.phpt new file mode 100644 index 00000000000..ecd32669e9d --- /dev/null +++ b/tests/end-to-end/phpt/parse-ini-env-section.phpt @@ -0,0 +1,22 @@ +--TEST-- +Can parse --INI-- and --ENV-- sections +--SKIPIF-- + +--EXPECT-- +string(5) "1.337" +bool(false) +string(19) "phpunit-env-section" diff --git a/tests/end-to-end/phpt/phpt-args.phpt b/tests/end-to-end/phpt/phpt-args.phpt new file mode 100644 index 00000000000..f1f35cdde87 --- /dev/null +++ b/tests/end-to-end/phpt/phpt-args.phpt @@ -0,0 +1,11 @@ +--TEST-- +PHPT runner supports ARGS section +--ARGS-- +help +--FILE-- + 0 && $argv[1] == 'help') { + print 'Help'; +} +--EXPECT-- +Help diff --git a/tests/end-to-end/phpt/phpt-clean-parse-error.phpt b/tests/end-to-end/phpt/phpt-clean-parse-error.phpt new file mode 100644 index 00000000000..6ec33994151 --- /dev/null +++ b/tests/end-to-end/phpt/phpt-clean-parse-error.phpt @@ -0,0 +1,28 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5991 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) CLEAN section triggered a parse error: +Parse error: Unmatched '}' in Standard input code on line 3 + + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/phpt/phpt-env.phpt b/tests/end-to-end/phpt/phpt-env.phpt new file mode 100644 index 00000000000..0d43bc9a64e --- /dev/null +++ b/tests/end-to-end/phpt/phpt-env.phpt @@ -0,0 +1,14 @@ +--TEST-- +PHPT runner should support ENV section +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +I 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 1, Assertions: 1, Incomplete: 1. diff --git a/tests/end-to-end/regression/1149.phpt b/tests/end-to-end/regression/1149.phpt new file mode 100644 index 00000000000..0196b446e35 --- /dev/null +++ b/tests/end-to-end/regression/1149.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-1149: Test swallows output buffer when run in a separate process +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +1.2. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/1149/Issue1149Test.php b/tests/end-to-end/regression/1149/Issue1149Test.php new file mode 100644 index 00000000000..e5eb518bf91 --- /dev/null +++ b/tests/end-to-end/regression/1149/Issue1149Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +class Issue1149Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + print '1'; + } + + #[RunInSeparateProcess] + public function testTwo(): void + { + $this->assertTrue(true); + print '2'; + } +} diff --git a/tests/end-to-end/regression/1335.phpt b/tests/end-to-end/regression/1335.phpt new file mode 100644 index 00000000000..374fb70153b --- /dev/null +++ b/tests/end-to-end/regression/1335.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1335 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +............ 12 / 12 (100%) + +Time: %s, Memory: %s + +OK (12 tests, 12 assertions) diff --git a/tests/end-to-end/regression/1335/Issue1335Test.php b/tests/end-to-end/regression/1335/Issue1335Test.php new file mode 100644 index 00000000000..d706d44d98c --- /dev/null +++ b/tests/end-to-end/regression/1335/Issue1335Test.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +#[PreserveGlobalState(true)] +class Issue1335Test extends TestCase +{ + public function testGlobalString(): void + { + $this->assertEquals('Hello', $GLOBALS['globalString']); + } + + public function testGlobalIntTruthy(): void + { + $this->assertEquals(1, $GLOBALS['globalIntTruthy']); + } + + public function testGlobalIntFalsey(): void + { + $this->assertEquals(0, $GLOBALS['globalIntFalsey']); + } + + public function testGlobalFloat(): void + { + $this->assertEquals(1.123, $GLOBALS['globalFloat']); + } + + public function testGlobalBoolTrue(): void + { + $this->assertTrue($GLOBALS['globalBoolTrue']); + } + + public function testGlobalBoolFalse(): void + { + $this->assertFalse($GLOBALS['globalBoolFalse']); + } + + public function testGlobalNull(): void + { + $this->assertEquals(null, $GLOBALS['globalNull']); + } + + public function testGlobalArray(): void + { + $this->assertEquals(['foo'], $GLOBALS['globalArray']); + } + + public function testGlobalNestedArray(): void + { + $this->assertEquals([['foo']], $GLOBALS['globalNestedArray']); + } + + public function testGlobalObject(): void + { + $this->assertEquals((object) ['foo' => 'bar'], $GLOBALS['globalObject']); + } + + public function testGlobalObjectWithBackSlashString(): void + { + $this->assertEquals((object) ['foo' => 'back\\slash'], $GLOBALS['globalObjectWithBackSlashString']); + } + + public function testGlobalObjectWithDoubleBackSlashString(): void + { + $this->assertEquals((object) ['foo' => 'back\\\\slash'], $GLOBALS['globalObjectWithDoubleBackSlashString']); + } +} diff --git a/tests/end-to-end/regression/1335/bootstrap1335.php b/tests/end-to-end/regression/1335/bootstrap1335.php new file mode 100644 index 00000000000..d2ec70e3e7a --- /dev/null +++ b/tests/end-to-end/regression/1335/bootstrap1335.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +$globalString = 'Hello'; +$globalIntTruthy = 1; +$globalIntFalsey = 0; +$globalFloat = 1.123; +$globalBoolTrue = true; +$globalBoolFalse = false; +$globalNull = null; +$globalArray = ['foo']; +$globalNestedArray = [['foo']]; +$globalObject = (object) ['foo' => 'bar']; +$globalObjectWithBackSlashString = (object) ['foo' => 'back\\slash']; +$globalObjectWithDoubleBackSlashString = (object) ['foo' => 'back\\\\slash']; diff --git a/tests/end-to-end/regression/1337.phpt b/tests/end-to-end/regression/1337.phpt new file mode 100644 index 00000000000..5b39de21008 --- /dev/null +++ b/tests/end-to-end/regression/1337.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1337 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/1337/Issue1337Test.php b/tests/end-to-end/regression/1337/Issue1337Test.php new file mode 100644 index 00000000000..9abd356fad9 --- /dev/null +++ b/tests/end-to-end/regression/1337/Issue1337Test.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class Issue1337Test extends TestCase +{ + public static function dataProvider(): array + { + return [ + 'c:\\' => [true], + // The following is commented out because it no longer works in PHP >= 8.1 + // 0.9 => [true], + ]; + } + + #[DataProvider('dataProvider')] + public function testProvider($a): void + { + $this->assertTrue($a); + } +} diff --git a/tests/end-to-end/regression/1374.phpt b/tests/end-to-end/regression/1374.phpt new file mode 100644 index 00000000000..ef6317ed968 --- /dev/null +++ b/tests/end-to-end/regression/1374.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1374 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +S 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 1, Assertions: 0, Skipped: 1. diff --git a/tests/end-to-end/regression/1374/Issue1374Test.php b/tests/end-to-end/regression/1374/Issue1374Test.php new file mode 100644 index 00000000000..70f32b3b7d4 --- /dev/null +++ b/tests/end-to-end/regression/1374/Issue1374Test.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpExtension('I_DO_NOT_EXIST')] +class Issue1374Test extends TestCase +{ + protected function setUp(): void + { + print __FUNCTION__; + } + + protected function tearDown(): void + { + print __FUNCTION__; + } + + public function testSomething(): void + { + $this->fail('This should not be reached'); + } +} diff --git a/tests/end-to-end/regression/1437.phpt b/tests/end-to-end/regression/1437.phpt new file mode 100644 index 00000000000..46b4bf3c29e --- /dev/null +++ b/tests/end-to-end/regression/1437.phpt @@ -0,0 +1,37 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1437 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue1437Test::testFailure +Failed asserting that false is true. + +%sIssue1437Test.php:%i + +-- + +There was 1 risky test: + +1) PHPUnit\TestFixture\Issue1437Test::testFailure +Test code or tested code did not close its own output buffers + +%sIssue1437Test.php:%i + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1, Risky: 1. diff --git a/tests/end-to-end/regression/1437/Issue1437Test.php b/tests/end-to-end/regression/1437/Issue1437Test.php new file mode 100644 index 00000000000..68eb31eb321 --- /dev/null +++ b/tests/end-to-end/regression/1437/Issue1437Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function ob_start; +use PHPUnit\Framework\TestCase; + +class Issue1437Test extends TestCase +{ + public function testFailure(): void + { + ob_start(); + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/1471.phpt b/tests/end-to-end/regression/1471.phpt new file mode 100644 index 00000000000..cd729c2857c --- /dev/null +++ b/tests/end-to-end/regression/1471.phpt @@ -0,0 +1,28 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1471 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue1471Test::testFailure +Failed asserting that false is true. + +%s%eIssue1471Test.php:%d + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/1471/Issue1471Test.php b/tests/end-to-end/regression/1471/Issue1471Test.php new file mode 100644 index 00000000000..af938693418 --- /dev/null +++ b/tests/end-to-end/regression/1471/Issue1471Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue1471Test extends TestCase +{ + public function testFailure(): void + { + $this->expectOutputString('*'); + + print '*'; + + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/1570.phpt b/tests/end-to-end/regression/1570.phpt new file mode 100644 index 00000000000..d49e876e880 --- /dev/null +++ b/tests/end-to-end/regression/1570.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1570 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +*R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\Issue1570Test::testOne +Test code or tested code printed unexpected output: * + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/end-to-end/regression/1570/Issue1570Test.php b/tests/end-to-end/regression/1570/Issue1570Test.php new file mode 100644 index 00000000000..c7c5f195f5a --- /dev/null +++ b/tests/end-to-end/regression/1570/Issue1570Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue1570Test extends TestCase +{ + public function testOne(): void + { + print '*'; + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/2085.phpt b/tests/end-to-end/regression/2085.phpt new file mode 100644 index 00000000000..72b320a7242 --- /dev/null +++ b/tests/end-to-end/regression/2085.phpt @@ -0,0 +1,43 @@ +--TEST-- +Test CLI flags --enforce-time-limit --default-time-limit +--DESCRIPTION-- +https://github.com/sebastianbergmann/phpunit/issues/2085 +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +R 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 risky test: + +1) PHPUnit\TestFixture\Issue2085Test::testShouldAbortSlowTestByEnforcingTimeLimit +This test was aborted after 1 second + +%s:%d + +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/end-to-end/regression/2085/Issue2085Test.php b/tests/end-to-end/regression/2085/Issue2085Test.php new file mode 100644 index 00000000000..43dbcca09ef --- /dev/null +++ b/tests/end-to-end/regression/2085/Issue2085Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function sleep; +use PHPUnit\Framework\TestCase; + +class Issue2085Test extends TestCase +{ + public function testShouldAbortSlowTestByEnforcingTimeLimit(): void + { + $this->assertTrue(true); + sleep(2); + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/2137-filter.phpt b/tests/end-to-end/regression/2137-filter.phpt new file mode 100644 index 00000000000..dbbe8c831d7 --- /dev/null +++ b/tests/end-to-end/regression/2137-filter.phpt @@ -0,0 +1,38 @@ +--TEST-- +#2137: Error message for invalid dataprovider +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There were 2 PHPUnit errors: + +1) PHPUnit\TestFixture\Issue2137Test::testBrandService +The data provider specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid +Data set #0 provided by PHPUnit\TestFixture\Issue2137Test::provideBrandService is invalid, expected array but got stdClass + +%s:%d + +2) PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid +The data provider specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid +Data set #0 provided by PHPUnit\TestFixture\Issue2137Test::provideBrandService is invalid, expected array but got stdClass + +%s:%d + +-- + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\Issue2137Test". + +No tests executed! diff --git a/tests/end-to-end/regression/2137-no_filter.phpt b/tests/end-to-end/regression/2137-no_filter.phpt new file mode 100644 index 00000000000..0bbb311434a --- /dev/null +++ b/tests/end-to-end/regression/2137-no_filter.phpt @@ -0,0 +1,36 @@ +--TEST-- +#2137: Error message for invalid dataprovider +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There were 2 PHPUnit errors: + +1) PHPUnit\TestFixture\Issue2137Test::testBrandService +The data provider specified for PHPUnit\TestFixture\Issue2137Test::testBrandService is invalid +Data set #0 provided by PHPUnit\TestFixture\Issue2137Test::provideBrandService is invalid, expected array but got stdClass + +%s:%d + +2) PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid +The data provider specified for PHPUnit\TestFixture\Issue2137Test::testSomethingElseInvalid is invalid +Data set #0 provided by PHPUnit\TestFixture\Issue2137Test::provideBrandService is invalid, expected array but got stdClass + +%s:%d + +-- + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\Issue2137Test". + +No tests executed! diff --git a/tests/end-to-end/regression/2137/Issue2137Test.php b/tests/end-to-end/regression/2137/Issue2137Test.php new file mode 100644 index 00000000000..f046b562d42 --- /dev/null +++ b/tests/end-to-end/regression/2137/Issue2137Test.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use SebastianBergmann\RecursionContext\InvalidArgumentException; +use stdClass; + +class Issue2137Test extends TestCase +{ + public static function provideBrandService() + { + return [ + // [true, true] + new stdClass, // not valid + ]; + } + + /** + * @throws Exception + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + #[DataProvider('provideBrandService')] + public function testBrandService($provided, $expected): void + { + $this->assertSame($provided, $expected); + } + + /** + * @throws \Exception + * @throws ExpectationFailedException + * @throws InvalidArgumentException + */ + #[DataProvider('provideBrandService')] + public function testSomethingElseInvalid($provided, $expected): void + { + $this->assertSame($provided, $expected); + } +} diff --git a/tests/end-to-end/regression/2145.phpt b/tests/end-to-end/regression/2145.phpt new file mode 100644 index 00000000000..2aa2266ec33 --- /dev/null +++ b/tests/end-to-end/regression/2145.phpt @@ -0,0 +1,29 @@ +--TEST-- +--stop-on-failure fails to stop on PHP 7 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\Issue2145Test +Exception: message + +%s:%d + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/2145/Issue2145Test.php b/tests/end-to-end/regression/2145/Issue2145Test.php new file mode 100644 index 00000000000..3eabdf10491 --- /dev/null +++ b/tests/end-to-end/regression/2145/Issue2145Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +class Issue2145Test extends TestCase +{ + public static function setUpBeforeClass(): void + { + throw new Exception('message'); + } + + public function testOne(): void + { + } + + public function testTwo(): void + { + } +} diff --git a/tests/end-to-end/regression/2155-no-expects-log.phpt b/tests/end-to-end/regression/2155-no-expects-log.phpt new file mode 100644 index 00000000000..af9e476d934 --- /dev/null +++ b/tests/end-to-end/regression/2155-no-expects-log.phpt @@ -0,0 +1,26 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/2155 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +logged a side effect +. 1 / 1 (100%) + +Time: %s, Memory: %s + +Issue2155Test_No Expects Log (PHPUnit\TestFixture\Issue2155\Issue2155Test_NoExpectsLog) + ✔ One + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/2155/Issue2155Test_NoExpectsLog.php b/tests/end-to-end/regression/2155/Issue2155Test_NoExpectsLog.php new file mode 100644 index 00000000000..341bdba4f52 --- /dev/null +++ b/tests/end-to-end/regression/2155/Issue2155Test_NoExpectsLog.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue2155; + +use function error_log; +use PHPUnit\Framework\TestCase; + +class Foo +{ + public function doFoo() + { + error_log('logged a side effect'); + + return ''; + } +} + +final class Issue2155Test_NoExpectsLog extends TestCase +{ + public function testOne(): void + { + $foo = new Foo; + + $this->assertSame('', $foo->doFoo()); + } +} diff --git a/tests/end-to-end/regression/2158.phpt b/tests/end-to-end/regression/2158.phpt new file mode 100644 index 00000000000..bca1c290394 --- /dev/null +++ b/tests/end-to-end/regression/2158.phpt @@ -0,0 +1,20 @@ +--TEST-- +#2158: Failure to run tests in separate processes if a file included into main process contains constant definition +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/2158/Issue2158Test.php b/tests/end-to-end/regression/2158/Issue2158Test.php new file mode 100644 index 00000000000..4c755287940 --- /dev/null +++ b/tests/end-to-end/regression/2158/Issue2158Test.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function defined; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +#[PreserveGlobalState(true)] +class Issue2158Test extends TestCase +{ + /** + * Set constant in main process. + */ + public function testSomething(): void + { + include __DIR__ . '/constant.inc'; + $this->assertTrue(true); + } + + /** + * Constant defined previously in main process constant should be available and + * no errors should be yielded by reload of included files. + */ + #[RunInSeparateProcess] + public function testSomethingElse(): void + { + $this->assertTrue(defined('TEST_CONSTANT')); + } +} diff --git a/tests/end-to-end/regression/2158/constant.inc b/tests/end-to-end/regression/2158/constant.inc new file mode 100644 index 00000000000..e9eb2cac8d6 --- /dev/null +++ b/tests/end-to-end/regression/2158/constant.inc @@ -0,0 +1,4 @@ + diff --git a/tests/end-to-end/regression/2380.phpt b/tests/end-to-end/regression/2380.phpt new file mode 100644 index 00000000000..6c7513a79eb --- /dev/null +++ b/tests/end-to-end/regression/2380.phpt @@ -0,0 +1,20 @@ +--TEST-- +#2380: Data Providers cannot be generators anymore +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/2380/Issue2380Test.php b/tests/end-to-end/regression/2380/Issue2380Test.php new file mode 100644 index 00000000000..bd1eafe6eb3 --- /dev/null +++ b/tests/end-to-end/regression/2380/Issue2380Test.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Generator; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class Issue2380Test extends TestCase +{ + public static function generatorData(): Generator + { + yield ['testing']; + } + + #[DataProvider('generatorData')] + public function testGeneratorProvider($data): void + { + $this->assertNotEmpty($data); + } +} diff --git a/tests/end-to-end/regression/2435.phpt b/tests/end-to-end/regression/2435.phpt new file mode 100644 index 00000000000..d942126e12a --- /dev/null +++ b/tests/end-to-end/regression/2435.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-2435: Test empty @group annotation +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/2435/Issue2435Test.php b/tests/end-to-end/regression/2435/Issue2435Test.php new file mode 100644 index 00000000000..1f656884525 --- /dev/null +++ b/tests/end-to-end/regression/2435/Issue2435Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue2435Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/2448-existing-test.phpt b/tests/end-to-end/regression/2448-existing-test.phpt new file mode 100644 index 00000000000..fefd18a6381 --- /dev/null +++ b/tests/end-to-end/regression/2448-existing-test.phpt @@ -0,0 +1,25 @@ +--TEST-- +#2448: Weird error when trying to run `Test` from `Test.php` but `Test.php` does not exist +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) +--CLEAN-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Test file "SomeNonExistingTest.php" not found +--CLEAN-- + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/2724-diff-pid-from-parent-process.phpt b/tests/end-to-end/regression/2724-diff-pid-from-parent-process.phpt new file mode 100644 index 00000000000..4376fe283c0 --- /dev/null +++ b/tests/end-to-end/regression/2724-diff-pid-from-parent-process.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-2724: Missing initialization of setRunClassInSeparateProcess() for tests without data providers +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 3 assertions) diff --git a/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php b/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php new file mode 100644 index 00000000000..6e197fa5d5e --- /dev/null +++ b/tests/end-to-end/regression/2724/SeparateClassRunMethodInNewProcessTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function file_exists; +use function file_get_contents; +use function getmypid; +use function unlink; +use PHPUnit\Framework\TestCase; + +final class SeparateClassRunMethodInNewProcessTest extends TestCase +{ + public const string PROCESS_ID_FILE_PATH = __DIR__ . '/parent_process_id.txt'; + public const int INITIAL_PARENT_PROCESS_ID = 0; + public const int INITIAL_PROCESS_ID = 1; + public static $parentProcessId = self::INITIAL_PARENT_PROCESS_ID; + public static $processId = self::INITIAL_PROCESS_ID; + + public static function setUpBeforeClass(): void + { + if (file_exists(self::PROCESS_ID_FILE_PATH)) { + self::$parentProcessId = (int) file_get_contents(self::PROCESS_ID_FILE_PATH); + } + } + + public static function tearDownAfterClass(): void + { + if (file_exists(self::PROCESS_ID_FILE_PATH)) { + unlink(self::PROCESS_ID_FILE_PATH); + } + } + + public function testTestMethodIsRunInSeparateProcess(): void + { + self::$processId = getmypid(); + + $this->assertNotSame(self::INITIAL_PROCESS_ID, self::$processId); + $this->assertNotSame(self::INITIAL_PARENT_PROCESS_ID, self::$parentProcessId); + $this->assertNotSame(self::$processId, self::$parentProcessId); + } +} diff --git a/tests/end-to-end/regression/2725-separate-class-before-after-pid.phpt b/tests/end-to-end/regression/2725-separate-class-before-after-pid.phpt new file mode 100644 index 00000000000..1521a31b913 --- /dev/null +++ b/tests/end-to-end/regression/2725-separate-class-before-after-pid.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-2725: Verify that @runClassInSeparateProcess runs @beforeclass and @afterclass methods in the same process as test methods. +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/2725/BeforeAfterClassPidTest.php b/tests/end-to-end/regression/2725/BeforeAfterClassPidTest.php new file mode 100644 index 00000000000..66c91828d99 --- /dev/null +++ b/tests/end-to-end/regression/2725/BeforeAfterClassPidTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue2725; + +use function getmypid; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\TestCase; + +class BeforeAfterClassPidTest extends TestCase +{ + public const PID_VARIABLE = 'current_pid'; + + #[BeforeClass] + public static function showPidBefore(): void + { + $GLOBALS[static::PID_VARIABLE] = getmypid(); + } + + #[AfterClass] + public static function showPidAfter(): void + { + if ($GLOBALS[static::PID_VARIABLE] - getmypid() !== 0) { + print "\n@afterClass output - PID difference should be zero!"; + } + + unset($GLOBALS[static::PID_VARIABLE]); + } + + public function testMethod1WithItsBeforeAndAfter(): void + { + $this->assertEquals($GLOBALS[static::PID_VARIABLE], getmypid()); + } + + public function testMethod2WithItsBeforeAndAfter(): void + { + $this->assertEquals($GLOBALS[static::PID_VARIABLE], getmypid()); + } +} diff --git a/tests/end-to-end/regression/2731.phpt b/tests/end-to-end/regression/2731.phpt new file mode 100644 index 00000000000..fca0836c1e2 --- /dev/null +++ b/tests/end-to-end/regression/2731.phpt @@ -0,0 +1,27 @@ +--TEST-- +GH-2731: Empty exception message cannot be expected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue2731Test::testOne +Failed asserting that exception message is empty but is 'message'. + +FAILURES! +Tests: 1, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/regression/2731/Issue2731Test.php b/tests/end-to-end/regression/2731/Issue2731Test.php new file mode 100644 index 00000000000..afb2aa6bc06 --- /dev/null +++ b/tests/end-to-end/regression/2731/Issue2731Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +class Issue2731Test extends TestCase +{ + public function testOne(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage(''); + + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/2811.phpt b/tests/end-to-end/regression/2811.phpt new file mode 100644 index 00000000000..2ee754d84f4 --- /dev/null +++ b/tests/end-to-end/regression/2811.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-2811: expectExceptionMessage() does not work without expectException() +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/2811/Issue2811Test.php b/tests/end-to-end/regression/2811/Issue2811Test.php new file mode 100644 index 00000000000..b92275c533e --- /dev/null +++ b/tests/end-to-end/regression/2811/Issue2811Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\TestCase; + +class Issue2811Test extends TestCase +{ + public function testOne(): void + { + $this->expectExceptionMessage('hello'); + + throw new Exception('hello'); + } +} diff --git a/tests/end-to-end/regression/2830.phpt b/tests/end-to-end/regression/2830.phpt new file mode 100644 index 00000000000..f16b86f8934 --- /dev/null +++ b/tests/end-to-end/regression/2830.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-2830: @runClassInSeparateProcess fails for tests with a data provider +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/2830/Issue2830Test.php b/tests/end-to-end/regression/2830/Issue2830Test.php new file mode 100644 index 00000000000..b9c55c6cc50 --- /dev/null +++ b/tests/end-to-end/regression/2830/Issue2830Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class Issue2830Test extends TestCase +{ + public static function simpleDataProvider(): array + { + return [ + ['foo'], + ]; + } + + #[DataProvider('simpleDataProvider')] + public function testMethodUsesDataProvider(string $foo): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/2833.phpt b/tests/end-to-end/regression/2833.phpt new file mode 100644 index 00000000000..77b74fc40ec --- /dev/null +++ b/tests/end-to-end/regression/2833.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/2833 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/2972.phpt b/tests/end-to-end/regression/2972.phpt new file mode 100644 index 00000000000..396cf8a8df6 --- /dev/null +++ b/tests/end-to-end/regression/2972.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-2972: Test suite shouldn't fail when it contains both *.phpt files and unconventionally named tests +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/2972/issue-2972-test.phpt b/tests/end-to-end/regression/2972/issue-2972-test.phpt new file mode 100644 index 00000000000..f8cc0ef9b6a --- /dev/null +++ b/tests/end-to-end/regression/2972/issue-2972-test.phpt @@ -0,0 +1,10 @@ +--TEST-- +Just a sample test for issue 2972, does not actually test anything +--FILE-- + +===DONE=== +--EXPECT-- +Hello world +===DONE=== diff --git a/tests/end-to-end/regression/2972/unconventiallyNamedIssue2972Test.php b/tests/end-to-end/regression/2972/unconventiallyNamedIssue2972Test.php new file mode 100644 index 00000000000..0747cb10080 --- /dev/null +++ b/tests/end-to-end/regression/2972/unconventiallyNamedIssue2972Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class unconventiallyNamedIssue2972Test extends TestCase +{ + public function testHello(): void + { + $this->assertNotEmpty('Hello world!'); + } +} diff --git a/tests/end-to-end/regression/3093/Issue3093Test.php b/tests/end-to-end/regression/3093/Issue3093Test.php new file mode 100644 index 00000000000..40b1a86e8d9 --- /dev/null +++ b/tests/end-to-end/regression/3093/Issue3093Test.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +class Issue3093Test extends TestCase +{ + public static function someDataProvider(): array + { + return [['some values']]; + } + + public function testFirstWithoutDependencies(): void + { + $this->assertTrue(true); + } + + #[Depends('testFirstWithoutDependencies')] + #[DataProvider('someDataProvider')] + public function testSecondThatDependsOnFirstAndDataprovider($value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/3093/issue-3093-test.phpt b/tests/end-to-end/regression/3093/issue-3093-test.phpt new file mode 100644 index 00000000000..233c5171bff --- /dev/null +++ b/tests/end-to-end/regression/3093/issue-3093-test.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/3093 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/3156/Issue3156Test.php b/tests/end-to-end/regression/3156/Issue3156Test.php new file mode 100644 index 00000000000..f43dc312371 --- /dev/null +++ b/tests/end-to-end/regression/3156/Issue3156Test.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; +use stdClass; + +class Issue3156Test extends TestCase +{ + public static function dataSelectOperatorsProvider(): array + { + return [ + ['1'], + ['2'], + ]; + } + + public function testConstants(): stdClass + { + $this->assertStringEndsWith('/', '/'); + + return new stdClass; + } + + #[Depends('testConstants')] + #[DataProvider('dataSelectOperatorsProvider')] + public function testDependsRequire(string $val, stdClass $obj): void + { + $this->assertStringEndsWith('/', '/'); + } +} diff --git a/tests/end-to-end/regression/3881.phpt b/tests/end-to-end/regression/3881.phpt new file mode 100644 index 00000000000..a06081409ee --- /dev/null +++ b/tests/end-to-end/regression/3881.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/3881 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/3881/Issue3881Test.php b/tests/end-to-end/regression/3881/Issue3881Test.php new file mode 100644 index 00000000000..330e3d76435 --- /dev/null +++ b/tests/end-to-end/regression/3881/Issue3881Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +abstract class AbstractIssue3881Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} + +final class Issue3881Test extends AbstractIssue3881Test +{ +} diff --git a/tests/end-to-end/regression/3904.phpt b/tests/end-to-end/regression/3904.phpt new file mode 100644 index 00000000000..d437b7a48fa --- /dev/null +++ b/tests/end-to-end/regression/3904.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/3904 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/3904/Issue3904Test.php b/tests/end-to-end/regression/3904/Issue3904Test.php new file mode 100644 index 00000000000..6c5f792ff59 --- /dev/null +++ b/tests/end-to-end/regression/3904/Issue3904Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Bar extends TestCase +{ +} + +final class Issue3904Test extends Bar +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/3983-1.phpt b/tests/end-to-end/regression/3983-1.phpt new file mode 100644 index 00000000000..082997723a8 --- /dev/null +++ b/tests/end-to-end/regression/3983-1.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit 3983 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/3983-2.phpt b/tests/end-to-end/regression/3983-2.phpt new file mode 100644 index 00000000000..965b64de474 --- /dev/null +++ b/tests/end-to-end/regression/3983-2.phpt @@ -0,0 +1,20 @@ +--TEST-- +phpunit 3983/ +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/3983/Issue3983Test.php b/tests/end-to-end/regression/3983/Issue3983Test.php new file mode 100644 index 00000000000..3ec4d18289e --- /dev/null +++ b/tests/end-to-end/regression/3983/Issue3983Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Issue3983Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/4232.phpt b/tests/end-to-end/regression/4232.phpt new file mode 100644 index 00000000000..be898dcb671 --- /dev/null +++ b/tests/end-to-end/regression/4232.phpt @@ -0,0 +1,23 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4232 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/4232/Issue4232Test.php b/tests/end-to-end/regression/4232/Issue4232Test.php new file mode 100644 index 00000000000..ef7dbf8e9ad --- /dev/null +++ b/tests/end-to-end/regression/4232/Issue4232Test.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +final class Issue4232Test extends ParentIssue4232Test +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/4232/ParentIssue4232Test.php b/tests/end-to-end/regression/4232/ParentIssue4232Test.php new file mode 100644 index 00000000000..e8ebc00da90 --- /dev/null +++ b/tests/end-to-end/regression/4232/ParentIssue4232Test.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class ParentIssue4232Test extends TestCase +{ +} diff --git a/tests/end-to-end/regression/433.phpt b/tests/end-to-end/regression/433.phpt new file mode 100644 index 00000000000..a82286c3d02 --- /dev/null +++ b/tests/end-to-end/regression/433.phpt @@ -0,0 +1,31 @@ +--TEST-- +GH-433: expectOutputString not completely working as expected +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..F 3 / 3 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue433Test::testNotMatchingOutput +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +FAILURES! +Tests: 3, Assertions: 3, Failures: 1. diff --git a/tests/end-to-end/regression/433/Issue433Test.php b/tests/end-to-end/regression/433/Issue433Test.php new file mode 100644 index 00000000000..d4f1654bea8 --- /dev/null +++ b/tests/end-to-end/regression/433/Issue433Test.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue433Test extends TestCase +{ + public function testOutputWithExpectationBefore(): void + { + $this->expectOutputString('test'); + print 'test'; + } + + public function testOutputWithExpectationAfter(): void + { + print 'test'; + $this->expectOutputString('test'); + } + + public function testNotMatchingOutput(): void + { + print 'bar'; + $this->expectOutputString('foo'); + } +} diff --git a/tests/end-to-end/regression/4347.phpt b/tests/end-to-end/regression/4347.phpt new file mode 100644 index 00000000000..8793f115f81 --- /dev/null +++ b/tests/end-to-end/regression/4347.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4347 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/4347/TestIssue4347.php b/tests/end-to-end/regression/4347/TestIssue4347.php new file mode 100644 index 00000000000..a17c96a0b12 --- /dev/null +++ b/tests/end-to-end/regression/4347/TestIssue4347.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +class TestIssue4347 extends TestCase +{ + public static function thisMethodDataProvider() + { + return [ + [new Exception('my message')], + ]; + } + + #[DataProvider('thisMethodDataProvider')] + public function testThisMethod(Exception $expectedException): void + { + $this->assertSame('my message', $expectedException->getMessage()); + } +} diff --git a/tests/end-to-end/regression/4376.phpt b/tests/end-to-end/regression/4376.phpt new file mode 100644 index 00000000000..3f090f78114 --- /dev/null +++ b/tests/end-to-end/regression/4376.phpt @@ -0,0 +1,30 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4376 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\Test::testOne +Error: Class %sC%s not found + +%sTest.php:%d + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/4376/phpunit.xml b/tests/end-to-end/regression/4376/phpunit.xml new file mode 100644 index 00000000000..d59f95ea8ba --- /dev/null +++ b/tests/end-to-end/regression/4376/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/4376/tests/Test.php b/tests/end-to-end/regression/4376/tests/Test.php new file mode 100644 index 00000000000..0a4afa88f23 --- /dev/null +++ b/tests/end-to-end/regression/4376/tests/Test.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use C; +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + public function testOne(): void + { + $o = new C; + } +} diff --git a/tests/end-to-end/regression/4391-separate-class-requires-in-class.phpt b/tests/end-to-end/regression/4391-separate-class-requires-in-class.phpt new file mode 100644 index 00000000000..e92bbdc82bc --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-class-requires-in-class.phpt @@ -0,0 +1,32 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +SS 2 / 2 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 2, Assertions: 0, Skipped: 2. diff --git a/tests/end-to-end/regression/4391-separate-class-requires-in-method.phpt b/tests/end-to-end/regression/4391-separate-class-requires-in-method.phpt new file mode 100644 index 00000000000..a003bf341a4 --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-class-requires-in-method.phpt @@ -0,0 +1,32 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +SS 2 / 2 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 2, Assertions: 0, Skipped: 2. diff --git a/tests/end-to-end/regression/4391-separate-requires-in-class.phpt b/tests/end-to-end/regression/4391-separate-requires-in-class.phpt new file mode 100644 index 00000000000..a05dbe9baa6 --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-requires-in-class.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +S 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 1, Assertions: 0, Skipped: 1. diff --git a/tests/end-to-end/regression/4391-separate-requires-in-method.phpt b/tests/end-to-end/regression/4391-separate-requires-in-method.phpt new file mode 100644 index 00000000000..6ff019b69a4 --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-requires-in-method.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +S 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 1, Assertions: 0, Skipped: 1. diff --git a/tests/end-to-end/regression/4391-separate-tests-requires-in-class.phpt b/tests/end-to-end/regression/4391-separate-tests-requires-in-class.phpt new file mode 100644 index 00000000000..1c78606064a --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-tests-requires-in-class.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +SS 2 / 2 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 2, Assertions: 0, Skipped: 2. diff --git a/tests/end-to-end/regression/4391-separate-tests-requires-in-method.phpt b/tests/end-to-end/regression/4391-separate-tests-requires-in-method.phpt new file mode 100644 index 00000000000..2f39ecc322b --- /dev/null +++ b/tests/end-to-end/regression/4391-separate-tests-requires-in-method.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4391 +--INI-- +disable_functions=proc_open +--FILE-- +setValue(null, $version); +(new PHPUnit\TextUI\Application)->run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +SS 2 / 2 (100%) + +Time: %s, Memory: %s + +OK, but some tests were skipped! +Tests: 2, Assertions: 0, Skipped: 2. diff --git a/tests/end-to-end/regression/4391/RunClassInSeparateProcessClassTest.php b/tests/end-to-end/regression/4391/RunClassInSeparateProcessClassTest.php new file mode 100644 index 00000000000..2362f0842c1 --- /dev/null +++ b/tests/end-to-end/regression/4391/RunClassInSeparateProcessClassTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpunit('< 10')] +final class RunClassInSeparateProcessClassTest extends TestCase +{ + public function testOne(): void + { + throw new Exception('message'); + } + + public function testTwo(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/4391/RunClassInSeparateProcessMethodTest.php b/tests/end-to-end/regression/4391/RunClassInSeparateProcessMethodTest.php new file mode 100644 index 00000000000..0857d22caad --- /dev/null +++ b/tests/end-to-end/regression/4391/RunClassInSeparateProcessMethodTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\TestCase; + +final class RunClassInSeparateProcessMethodTest extends TestCase +{ + #[RequiresPhpunit('< 10')] + public function testOne(): void + { + throw new Exception('message'); + } + + #[RequiresPhpunit('< 10')] + public function testTwo(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/4391/RunInSeparateProcessClassTest.php b/tests/end-to-end/regression/4391/RunInSeparateProcessClassTest.php new file mode 100644 index 00000000000..9e7df4d1c63 --- /dev/null +++ b/tests/end-to-end/regression/4391/RunInSeparateProcessClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +#[RequiresPhpunit('< 10')] +final class RunInSeparateProcessClassTest extends TestCase +{ + #[RunInSeparateProcess] + public function testOne(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/4391/RunInSeparateProcessMethodTest.php b/tests/end-to-end/regression/4391/RunInSeparateProcessMethodTest.php new file mode 100644 index 00000000000..88fcd68fb39 --- /dev/null +++ b/tests/end-to-end/regression/4391/RunInSeparateProcessMethodTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class RunInSeparateProcessMethodTest extends TestCase +{ + #[RunInSeparateProcess] + #[RequiresPhpunit('< 10')] + public function testOne(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesClassTest.php b/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesClassTest.php new file mode 100644 index 00000000000..b6c5513ea0c --- /dev/null +++ b/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesClassTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +#[RequiresPhpunit('< 10')] +final class RunTestsInSeparateProcessesClassTest extends TestCase +{ + public function testOne(): void + { + throw new Exception('message'); + } + + public function testTwo(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesMethodTest.php b/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesMethodTest.php new file mode 100644 index 00000000000..9a6dbe62ddb --- /dev/null +++ b/tests/end-to-end/regression/4391/RunTestsInSeparateProcessesMethodTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue4391; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class RunTestsInSeparateProcessesMethodTest extends TestCase +{ + #[RequiresPhpunit('< 10')] + public function testOne(): void + { + throw new Exception('message'); + } + + #[RequiresPhpunit('< 10')] + public function testTwo(): void + { + throw new Exception('message'); + } +} diff --git a/tests/end-to-end/regression/445.phpt b/tests/end-to-end/regression/445.phpt new file mode 100644 index 00000000000..0ee0f1b2c93 --- /dev/null +++ b/tests/end-to-end/regression/445.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-455: expectOutputString not working in strict mode +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..F 3 / 3 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue445Test::testNotMatchingOutput +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ +-'foo' ++'bar' + +FAILURES! +Tests: 3, Assertions: 3, Failures: 1. diff --git a/tests/end-to-end/regression/445/Issue445Test.php b/tests/end-to-end/regression/445/Issue445Test.php new file mode 100644 index 00000000000..ae7549c1fe0 --- /dev/null +++ b/tests/end-to-end/regression/445/Issue445Test.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue445Test extends TestCase +{ + public function testOutputWithExpectationBefore(): void + { + $this->expectOutputString('test'); + print 'test'; + } + + public function testOutputWithExpectationAfter(): void + { + print 'test'; + $this->expectOutputString('test'); + } + + public function testNotMatchingOutput(): void + { + print 'bar'; + $this->expectOutputString('foo'); + } +} diff --git a/tests/end-to-end/regression/4498.phpt b/tests/end-to-end/regression/4498.phpt new file mode 100644 index 00000000000..cef20c59ebf --- /dev/null +++ b/tests/end-to-end/regression/4498.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4498 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/4498/Issue4498Test.php b/tests/end-to-end/regression/4498/Issue4498Test.php new file mode 100644 index 00000000000..cad6b0cf6a2 --- /dev/null +++ b/tests/end-to-end/regression/4498/Issue4498Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class issue4498test extends TestCase +{ + public function testFoo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/4620.phpt b/tests/end-to-end/regression/4620.phpt new file mode 100644 index 00000000000..54b399a58be --- /dev/null +++ b/tests/end-to-end/regression/4620.phpt @@ -0,0 +1,25 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/4620 +https://github.com/sebastianbergmann/phpunit/issues/4877 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Error in bootstrap script: PHPUnit\TestFixture\MyException: +Big boom. Big bada boom. +%a + +Previous error: Exception: +Previous boom. +%a diff --git a/tests/end-to-end/regression/4620/Issue4620Test.php b/tests/end-to-end/regression/4620/Issue4620Test.php new file mode 100644 index 00000000000..bf0d8fe904e --- /dev/null +++ b/tests/end-to-end/regression/4620/Issue4620Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Issue4620Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/4620/bootstrap.php b/tests/end-to-end/regression/4620/bootstrap.php new file mode 100644 index 00000000000..706c9d6e883 --- /dev/null +++ b/tests/end-to-end/regression/4620/bootstrap.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; + +final class MyException extends Exception +{ +} + +throw new MyException('Big boom. Big bada boom.', 0, new Exception('Previous boom.')); diff --git a/tests/end-to-end/regression/498.phpt b/tests/end-to-end/regression/498.phpt new file mode 100644 index 00000000000..61e56b77e78 --- /dev/null +++ b/tests/end-to-end/regression/498.phpt @@ -0,0 +1,26 @@ +--TEST-- +GH-498: The test methods won't be run if a dataProvider throws Exception and --group is added in command line +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\Issue498Test::shouldBeFalse +The data provider PHPUnit\TestFixture\Issue498Test::shouldBeFalseDataProvider specified for PHPUnit\TestFixture\Issue498Test::shouldBeFalse is invalid +Can't create the data + +%s:%d + +No tests executed! diff --git a/tests/end-to-end/regression/498/Issue498Test.php b/tests/end-to-end/regression/498/Issue498Test.php new file mode 100644 index 00000000000..a28111831a2 --- /dev/null +++ b/tests/end-to-end/regression/498/Issue498Test.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +class Issue498Test extends TestCase +{ + public static function shouldBeTrueDataProvider(): array + { + return [ + [true], + [false], + ]; + } + + public static function shouldBeFalseDataProvider(): array + { + throw new Exception("Can't create the data"); + } + + #[Test] + #[DataProvider('shouldBeTrueDataProvider')] + #[Group('falseOnly')] + public function shouldBeTrue($testData): void + { + $this->assertTrue(true); + } + + #[Test] + #[DataProvider('shouldBeFalseDataProvider')] + #[Group('trueOnly')] + public function shouldBeFalse($testData): void + { + $this->assertFalse(false); + } +} diff --git a/tests/end-to-end/regression/5020.phpt b/tests/end-to-end/regression/5020.phpt new file mode 100644 index 00000000000..696dfc424a8 --- /dev/null +++ b/tests/end-to-end/regression/5020.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-5020: Load PSR-0 tests +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5020/Under/Score/Issue5020Test.php b/tests/end-to-end/regression/5020/Under/Score/Issue5020Test.php new file mode 100644 index 00000000000..9c71d0befe8 --- /dev/null +++ b/tests/end-to-end/regression/5020/Under/Score/Issue5020Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +/* + * This file is part of PHPUnit. + * + * (c) Sebastian Bergmann + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +class Under_Score_Issue5020Test extends TestCase +{ + public function testTrue(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/503.phpt b/tests/end-to-end/regression/503.phpt new file mode 100644 index 00000000000..d0f0a31d9b1 --- /dev/null +++ b/tests/end-to-end/regression/503.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-503: assertEquals() Line Ending Differences Are Obscure +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue503Test::testCompareDifferentLineEndings +Failed asserting that two strings are identical. +--- Expected ++++ Actual +@@ @@ + #Warning: Strings contain different line endings! +-'foo ++'foo + ' + +%s:%i + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/503/Issue503Test.php b/tests/end-to-end/regression/503/Issue503Test.php new file mode 100644 index 00000000000..b0097799fc4 --- /dev/null +++ b/tests/end-to-end/regression/503/Issue503Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue503Test extends TestCase +{ + public function testCompareDifferentLineEndings(): void + { + $this->assertSame( + "foo\n", + "foo\r\n", + ); + } +} diff --git a/tests/end-to-end/regression/5138.phpt b/tests/end-to-end/regression/5138.phpt new file mode 100644 index 00000000000..1915872b48e --- /dev/null +++ b/tests/end-to-end/regression/5138.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5138 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\Issue5138Test::testOne +The data provider PHPUnit\TestFixture\Issue5138Test::provideData specified for PHPUnit\TestFixture\Issue5138Test::testOne is invalid +message + +%s:%d + +-- + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\Issue5138Test". + +No tests executed! diff --git a/tests/end-to-end/regression/5138/phpunit.xml b/tests/end-to-end/regression/5138/phpunit.xml new file mode 100644 index 00000000000..1689799b616 --- /dev/null +++ b/tests/end-to-end/regression/5138/phpunit.xml @@ -0,0 +1,9 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/5138/tests/Issue5138Test.php b/tests/end-to-end/regression/5138/tests/Issue5138Test.php new file mode 100644 index 00000000000..a2098c0cf30 --- /dev/null +++ b/tests/end-to-end/regression/5138/tests/Issue5138Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +final class Issue5138Test extends TestCase +{ + public static function provideData(): void + { + throw new RuntimeException('message'); + } + + #[DataProvider('provideData')] + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/regression/5157.phpt b/tests/end-to-end/regression/5157.phpt new file mode 100644 index 00000000000..6ea50448bef --- /dev/null +++ b/tests/end-to-end/regression/5157.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5157 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5157/phpunit.xml b/tests/end-to-end/regression/5157/phpunit.xml new file mode 100644 index 00000000000..a627748fe37 --- /dev/null +++ b/tests/end-to-end/regression/5157/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/5157/tests/Test.php b/tests/end-to-end/regression/5157/tests/Test.php new file mode 100644 index 00000000000..d601cbd458e --- /dev/null +++ b/tests/end-to-end/regression/5157/tests/Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +final class Test extends TestCase +{ + private static bool $variable = false; + + public static function setUpBeforeClass(): void + { + self::$variable = true; + } + + public function testOne(): void + { + $this->assertTrue(self::$variable); + } +} diff --git a/tests/end-to-end/regression/5165.phpt b/tests/end-to-end/regression/5165.phpt new file mode 100644 index 00000000000..1a22692db67 --- /dev/null +++ b/tests/end-to-end/regression/5165.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5165 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There was 1 skipped test suite: + +1) Issue5165Test +message + +No tests executed! diff --git a/tests/end-to-end/regression/5165/Issue5165Test.php b/tests/end-to-end/regression/5165/Issue5165Test.php new file mode 100644 index 00000000000..8aec1b54ac5 --- /dev/null +++ b/tests/end-to-end/regression/5165/Issue5165Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +final class Issue5165Test extends TestCase +{ + public static function setUpBeforeClass(): void + { + self::markTestSkipped('message'); + } + + public function testOne(): void + { + } + + public function testTwo(): void + { + } +} diff --git a/tests/end-to-end/regression/5172.phpt b/tests/end-to-end/regression/5172.phpt new file mode 100644 index 00000000000..7a0a720aa6c --- /dev/null +++ b/tests/end-to-end/regression/5172.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5172 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +Issue5172 (PHPUnit\TestFixture\Issue5172) + ✔ One + +There was 1 PHPUnit test runner deprecation: + +1) Your XML configuration validates against a deprecated schema. Migrate your XML configuration using "--migrate-configuration"! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/regression/5172/phpunit.xml b/tests/end-to-end/regression/5172/phpunit.xml new file mode 100644 index 00000000000..1cc108d9936 --- /dev/null +++ b/tests/end-to-end/regression/5172/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + + + + + diff --git a/tests/end-to-end/regression/5172/tests/Issue5172Test.php b/tests/end-to-end/regression/5172/tests/Issue5172Test.php new file mode 100644 index 00000000000..05ebfa20b33 --- /dev/null +++ b/tests/end-to-end/regression/5172/tests/Issue5172Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Issue5172Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5178.phpt b/tests/end-to-end/regression/5178.phpt new file mode 100644 index 00000000000..af550887ba3 --- /dev/null +++ b/tests/end-to-end/regression/5178.phpt @@ -0,0 +1,20 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5178 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +... 3 / 3 (100%) + +Time: %s, Memory: %s + +OK (3 tests, 3 assertions) diff --git a/tests/end-to-end/regression/5178/Issue5178Test.php b/tests/end-to-end/regression/5178/Issue5178Test.php new file mode 100644 index 00000000000..5d94aee31d1 --- /dev/null +++ b/tests/end-to-end/regression/5178/Issue5178Test.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +final class Issue5178Test extends TestCase +{ + public static function fooDataProvider(): array + { + return [ + 'foo 1' => ['Hello'], + 'foo 2' => ['World'], + ]; + } + + #[DataProvider('fooDataProvider')] + public function testFoo(string $input): void + { + $this->assertNotEmpty($input); + } + + #[Depends('testFoo')] + public function testBar(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5192.phpt b/tests/end-to-end/regression/5192.phpt new file mode 100644 index 00000000000..69627ad1d62 --- /dev/null +++ b/tests/end-to-end/regression/5192.phpt @@ -0,0 +1,17 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5192 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +No tests executed! diff --git a/tests/end-to-end/regression/5192/phpunit.xml b/tests/end-to-end/regression/5192/phpunit.xml new file mode 100644 index 00000000000..0dbd87e2524 --- /dev/null +++ b/tests/end-to-end/regression/5192/phpunit.xml @@ -0,0 +1,10 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/5192/tests/.gitkeep b/tests/end-to-end/regression/5192/tests/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/end-to-end/regression/5210.phpt b/tests/end-to-end/regression/5210.phpt new file mode 100644 index 00000000000..efac9e93d50 --- /dev/null +++ b/tests/end-to-end/regression/5210.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5210 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) Issue5210Test::testOne +Exception: test + +%s:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/regression/5210/Issue5210Test.php b/tests/end-to-end/regression/5210/Issue5210Test.php new file mode 100644 index 00000000000..7c56aaaee04 --- /dev/null +++ b/tests/end-to-end/regression/5210/Issue5210Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +final class Issue5210Test extends TestCase +{ + protected function tearDown(): void + { + throw new Exception('test'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5218.phpt b/tests/end-to-end/regression/5218.phpt new file mode 100644 index 00000000000..4d4eef6e8db --- /dev/null +++ b/tests/end-to-end/regression/5218.phpt @@ -0,0 +1,44 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5218 +--INI-- +pcov.directory=tests/end-to-end/regression/5218/src/ +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +OK (1 test, 1 assertion) + + +Code Coverage Report: + %s + + Summary: + Classes: 100.00% (1/1) + Methods: 100.00% (1/1) + Lines: 100.00% (1/1) + +PHPUnit\TestFixture\Issue5218\Issue5218 + Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1) diff --git a/tests/end-to-end/regression/5218/src/Issue5218.php b/tests/end-to-end/regression/5218/src/Issue5218.php new file mode 100644 index 00000000000..5c6fd9bc4b3 --- /dev/null +++ b/tests/end-to-end/regression/5218/src/Issue5218.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5218; + +final class Issue5218 +{ + public function returnMe(string $return): string + { + return $return; + } +} diff --git a/tests/end-to-end/regression/5218/tests/Issue5218Test.php b/tests/end-to-end/regression/5218/tests/Issue5218Test.php new file mode 100644 index 00000000000..0f2585ccdf4 --- /dev/null +++ b/tests/end-to-end/regression/5218/tests/Issue5218Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5218; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Issue5218::class)] +final class Issue5218Test extends TestCase +{ + public function testReturn(): void + { + $this->assertSame('foo', (new Issue5218)->returnMe('foo')); + } +} diff --git a/tests/end-to-end/regression/5234.phpt b/tests/end-to-end/regression/5234.phpt new file mode 100644 index 00000000000..39c04455135 --- /dev/null +++ b/tests/end-to-end/regression/5234.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5234 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5234/phpunit.xml b/tests/end-to-end/regression/5234/phpunit.xml new file mode 100644 index 00000000000..c84aeb637ad --- /dev/null +++ b/tests/end-to-end/regression/5234/phpunit.xml @@ -0,0 +1,14 @@ + + + + + tests + + + + + + + diff --git a/tests/end-to-end/regression/5234/tests/Issue5234Test.php b/tests/end-to-end/regression/5234/tests/Issue5234Test.php new file mode 100644 index 00000000000..aede3034053 --- /dev/null +++ b/tests/end-to-end/regression/5234/tests/Issue5234Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5234; + +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class Issue5234Test extends TestCase +{ + #[RunInSeparateProcess] + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5234/tests/bootstrap.php b/tests/end-to-end/regression/5234/tests/bootstrap.php new file mode 100644 index 00000000000..41202f7126d --- /dev/null +++ b/tests/end-to-end/regression/5234/tests/bootstrap.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +if (!\defined('CONST_TEST')) { + exit; +} diff --git a/tests/end-to-end/regression/5258.phpt b/tests/end-to-end/regression/5258.phpt new file mode 100644 index 00000000000..4d45223594a --- /dev/null +++ b/tests/end-to-end/regression/5258.phpt @@ -0,0 +1,39 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5258 +--FILE-- +run($_SERVER['argv']); + +print file_get_contents($junitFile); + +unlink($junitFile); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.S 2 / 2 (100%) + +Time: %s, Memory: %s MB + +OK, but some tests were skipped! +Tests: 2, Assertions: 1, Skipped: 1. + + + + + + + + + diff --git a/tests/end-to-end/regression/5258/Issue5258Test.php b/tests/end-to-end/regression/5258/Issue5258Test.php new file mode 100644 index 00000000000..8175c04eca6 --- /dev/null +++ b/tests/end-to-end/regression/5258/Issue5258Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5258; + +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class Issue5258Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + #[RunInSeparateProcess] + #[RequiresPhpExtension('notinstalled')] + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5278.phpt b/tests/end-to-end/regression/5278.phpt new file mode 100644 index 00000000000..9ec033e9fd8 --- /dev/null +++ b/tests/end-to-end/regression/5278.phpt @@ -0,0 +1,26 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5278 +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +bool(true) +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5278/Issue5278Test.php b/tests/end-to-end/regression/5278/Issue5278Test.php new file mode 100644 index 00000000000..5807be9684f --- /dev/null +++ b/tests/end-to-end/regression/5278/Issue5278Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5278; + +use function var_dump; +use PHPUnit\Framework\TestCase; + +final class Issue5278Test extends TestCase +{ + public function testOne(): void + { + $v = true; + + var_dump($v); + + $this->assertTrue($v); + } +} diff --git a/tests/end-to-end/regression/5287.phpt b/tests/end-to-end/regression/5287.phpt new file mode 100644 index 00000000000..db0517cd433 --- /dev/null +++ b/tests/end-to-end/regression/5287.phpt @@ -0,0 +1,52 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5287 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sMyClassTest.php) +Event Facade Sealed +Data Provider Method Called (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::provide for test method PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test) +Data Provider Method Finished for PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test: +- PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::provide +Test Suite Loaded (3 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (3 tests) +Test Suite Started (CLI Arguments, 3 tests) +Test Suite Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0) +Test Prepared (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0) +Test Passed (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0) +Test Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test#0) +Test Suite Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest::test, 1 test) +Test Suite Finished (PHPUnit\TestFixture\Issue5278\A\AnotherClassTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5278\B\MyClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5278\B\MyClassTest::test) +Test Prepared (PHPUnit\TestFixture\Issue5278\B\MyClassTest::test) +Test Failed (PHPUnit\TestFixture\Issue5278\B\MyClassTest::test) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Issue5278\B\MyClassTest::test) +Test Suite Finished (PHPUnit\TestFixture\Issue5278\B\MyClassTest, 1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5278\C\MyClassTest, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5278\C\MyClassTest::test) +Test Prepared (PHPUnit\TestFixture\Issue5278\C\MyClassTest::test) +Test Passed (PHPUnit\TestFixture\Issue5278\C\MyClassTest::test) +Test Finished (PHPUnit\TestFixture\Issue5278\C\MyClassTest::test) +Test Suite Finished (PHPUnit\TestFixture\Issue5278\C\MyClassTest, 1 test) +Test Suite Finished (CLI Arguments, 3 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/regression/5287/A/AnotherClassTest.php b/tests/end-to-end/regression/5287/A/AnotherClassTest.php new file mode 100644 index 00000000000..6026157d2d7 --- /dev/null +++ b/tests/end-to-end/regression/5287/A/AnotherClassTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5278\A; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\Issue5278\C\MyClassTest; + +final class AnotherClassTest extends TestCase +{ + public static function provide(): array + { + return [[MyClassTest::VALUE]]; + } + + #[DataProvider('provide')] + public function test(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/regression/5287/B/MyClassTest.php b/tests/end-to-end/regression/5287/B/MyClassTest.php new file mode 100644 index 00000000000..46843c217af --- /dev/null +++ b/tests/end-to-end/regression/5287/B/MyClassTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5278\B; + +use PHPUnit\Framework\TestCase; + +final class MyClassTest extends TestCase +{ + public function test(): void + { + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/5287/C/MyClassTest.php b/tests/end-to-end/regression/5287/C/MyClassTest.php new file mode 100644 index 00000000000..e1503a1d43d --- /dev/null +++ b/tests/end-to-end/regression/5287/C/MyClassTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5278\C; + +use PHPUnit\Framework\TestCase; + +final class MyClassTest extends TestCase +{ + public const bool VALUE = true; + + public function test(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5288.phpt b/tests/end-to-end/regression/5288.phpt new file mode 100644 index 00000000000..c53ed59aef8 --- /dev/null +++ b/tests/end-to-end/regression/5288.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5288 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +%s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5288/Issue5288Test.php b/tests/end-to-end/regression/5288/Issue5288Test.php new file mode 100644 index 00000000000..90358ccc5b1 --- /dev/null +++ b/tests/end-to-end/regression/5288/Issue5288Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5288; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue5288Test extends TestCase +{ + public static function provider(): array + { + return [[true]]; + } + + #[DataProvider('provider')] + public function testOne(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/regression/5340.phpt b/tests/end-to-end/regression/5340.phpt new file mode 100644 index 00000000000..b1a583432d1 --- /dev/null +++ b/tests/end-to-end/regression/5340.phpt @@ -0,0 +1,48 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5340 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +%s + +output printed from passing test +R +output printed from failing test +F 2 / 2 (100%) + +Time: %s, Memory: %s MB + +There was 1 failure: + +1) Issue5340Test::testTwo +Failed asserting that false is true. + +%s + +-- + +There were 2 risky tests: + +1) Issue5340Test::testOne +Test code or tested code printed unexpected output: output printed from passing test + +%s%eIssue5340Test.php:%d + +2) Issue5340Test::testTwo +Test code or tested code printed unexpected output: +output printed from failing test + +%s%eIssue5340Test.php:%d + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1, Risky: 2. diff --git a/tests/end-to-end/regression/5340/Issue5340Test.php b/tests/end-to-end/regression/5340/Issue5340Test.php new file mode 100644 index 00000000000..2820b8c7ac5 --- /dev/null +++ b/tests/end-to-end/regression/5340/Issue5340Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Framework\TestCase; + +final class Issue5340Test extends TestCase +{ + public function testOne(): void + { + print 'output printed from passing test' . \PHP_EOL; + + $this->assertTrue(true); + } + + public function testTwo(): void + { + print \PHP_EOL . 'output printed from failing test' . \PHP_EOL; + + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/5342.phpt b/tests/end-to-end/regression/5342.phpt new file mode 100644 index 00000000000..e8e6ee34b70 --- /dev/null +++ b/tests/end-to-end/regression/5342.phpt @@ -0,0 +1,37 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/1437 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue5342Test::testFailure +Failed asserting that false is true. + +%sIssue5342Test.php:%i + +-- + +There was 1 risky test: + +1) PHPUnit\TestFixture\Issue5342Test::testFailure +Test code or tested code closed output buffers other than its own + +%sIssue5342Test.php:%i + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1, Risky: 1. diff --git a/tests/end-to-end/regression/5342/Issue5342Test.php b/tests/end-to-end/regression/5342/Issue5342Test.php new file mode 100644 index 00000000000..d2c9a763ac2 --- /dev/null +++ b/tests/end-to-end/regression/5342/Issue5342Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function ob_end_clean; +use PHPUnit\Framework\TestCase; + +class Issue5342Test extends TestCase +{ + public function testFailure(): void + { + ob_end_clean(); + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/5351.phpt b/tests/end-to-end/regression/5351.phpt new file mode 100644 index 00000000000..dc81d61e84b --- /dev/null +++ b/tests/end-to-end/regression/5351.phpt @@ -0,0 +1,47 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5351 +--INI-- +pcov.directory=tests/end-to-end/regression/5351/src/ +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +W 1 / 1 (100%) + +Time: %s, Memory: %s MB + +1 test triggered 1 PHPUnit warning: + +1) PHPUnit\TestFixture\Issue5351\GreeterTest::testGreets +Class PHPUnit\TestFixture\Issue5351\DoesNotExist is not a valid target for code coverage + +%sGreeterTest.php:18 + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. + + +Code Coverage Report: + %s + + Summary: + Classes: 0.00% (0/1) + Methods: 0.00% (0/1) + Lines: 0.00% (0/1) + diff --git a/tests/end-to-end/regression/5351/phpunit.xml b/tests/end-to-end/regression/5351/phpunit.xml new file mode 100644 index 00000000000..5ff287ed27f --- /dev/null +++ b/tests/end-to-end/regression/5351/phpunit.xml @@ -0,0 +1,22 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/regression/5351/src/Greeter.php b/tests/end-to-end/regression/5351/src/Greeter.php new file mode 100644 index 00000000000..745685a4275 --- /dev/null +++ b/tests/end-to-end/regression/5351/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5351; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/regression/5351/tests/GreeterTest.php b/tests/end-to-end/regression/5351/tests/GreeterTest.php new file mode 100644 index 00000000000..d8131219204 --- /dev/null +++ b/tests/end-to-end/regression/5351/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5351; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass('PHPUnit\TestFixture\Issue5351\DoesNotExist')] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/regression/5364.phpt b/tests/end-to-end/regression/5364.phpt new file mode 100644 index 00000000000..9561ed4563b --- /dev/null +++ b/tests/end-to-end/regression/5364.phpt @@ -0,0 +1,25 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5364 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) Class PHPUnit\TestFixture\Issue5364\BarTest declared in %sBarTest.php does not extend PHPUnit\Framework\TestCase + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/regression/5364/BarTest.php b/tests/end-to-end/regression/5364/BarTest.php new file mode 100644 index 00000000000..06d42560271 --- /dev/null +++ b/tests/end-to-end/regression/5364/BarTest.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5364; + +final class BarTest +{ +} diff --git a/tests/end-to-end/regression/5364/FooTest.php b/tests/end-to-end/regression/5364/FooTest.php new file mode 100644 index 00000000000..7dfced85ee0 --- /dev/null +++ b/tests/end-to-end/regression/5364/FooTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5364; + +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5451.phpt b/tests/end-to-end/regression/5451.phpt new file mode 100644 index 00000000000..f06192cf85c --- /dev/null +++ b/tests/end-to-end/regression/5451.phpt @@ -0,0 +1,35 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5451 +--SKIPIF-- +run($_SERVER['argv'])); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\Issue5451\Issue5451Test::testWithErrorInDataProvider +The data provider PHPUnit\TestFixture\Issue5451\Issue5451Test::dataProviderThatTriggersPhpError specified for PHPUnit\TestFixture\Issue5451\Issue5451Test::testWithErrorInDataProvider is invalid +Call to a member function bar() on array + +%s%eIssue5451Test.php:26 + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. +int(2) diff --git a/tests/end-to-end/regression/5451/Issue5451Test.php b/tests/end-to-end/regression/5451/Issue5451Test.php new file mode 100644 index 00000000000..8879307ea09 --- /dev/null +++ b/tests/end-to-end/regression/5451/Issue5451Test.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5451; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue5451Test extends TestCase +{ + public static function dataProviderThatTriggersPhpError(): array + { + $foo = []; + $foo->bar(); + + return [[]]; + } + + #[DataProvider('dataProviderThatTriggersPhpError')] + public function testWithErrorInDataProvider(): void + { + } + + public function testThatWorks(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5456.phpt b/tests/end-to-end/regression/5456.phpt new file mode 100644 index 00000000000..1bec8c504aa --- /dev/null +++ b/tests/end-to-end/regression/5456.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5456 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5456/Issue5456Test.php b/tests/end-to-end/regression/5456/Issue5456Test.php new file mode 100644 index 00000000000..f98685f37f6 --- /dev/null +++ b/tests/end-to-end/regression/5456/Issue5456Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5456; + +use function ob_end_clean; +use function ob_start; +use PHPUnit\Framework\TestCase; + +final class Issue5456Test extends TestCase +{ + protected function tearDown(): void + { + ob_end_clean(); + } + + public function testOne(): void + { + $this->assertTrue(true); + + ob_start(); + } +} diff --git a/tests/end-to-end/regression/5493.phpt b/tests/end-to-end/regression/5493.phpt new file mode 100644 index 00000000000..c828eb60e5c --- /dev/null +++ b/tests/end-to-end/regression/5493.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5493 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue5493\Issue5493Test::testOne +Failed asserting that false is true. + +%sIssue5493Test.php:19 + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/5493/Issue5493Test.php b/tests/end-to-end/regression/5493/Issue5493Test.php new file mode 100644 index 00000000000..5be15f4d06f --- /dev/null +++ b/tests/end-to-end/regression/5493/Issue5493Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5493; + +use PHPUnit\Framework\TestCase; + +final class Issue5493Test extends TestCase +{ + protected function setUp(): void + { + /** @noinspection PhpUnitAssertCanBeReplacedWithFailInspection */ + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5498.phpt b/tests/end-to-end/regression/5498.phpt new file mode 100644 index 00000000000..120d32b7f4a --- /dev/null +++ b/tests/end-to-end/regression/5498.phpt @@ -0,0 +1,44 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5498 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Bootstrap Finished (%sTestCase.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (CLI Arguments, 1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5498\Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5498\Test::testOne) +Before Test Method Called (PHPUnit\TestFixture\Issue5498\Test::parentBefore) +Before Test Method Called (PHPUnit\TestFixture\Issue5498\Test::before) +Before Test Method Finished: +- PHPUnit\TestFixture\Issue5498\Test::parentBefore +- PHPUnit\TestFixture\Issue5498\Test::before +Test Prepared (PHPUnit\TestFixture\Issue5498\Test::testOne) +After Test Method Called (PHPUnit\TestFixture\Issue5498\Test::after) +After Test Method Called (PHPUnit\TestFixture\Issue5498\Test::parentAfter) +After Test Method Finished: +- PHPUnit\TestFixture\Issue5498\Test::after +- PHPUnit\TestFixture\Issue5498\Test::parentAfter +Test Passed (PHPUnit\TestFixture\Issue5498\Test::testOne) +Test Finished (PHPUnit\TestFixture\Issue5498\Test::testOne) +Test Suite Finished (PHPUnit\TestFixture\Issue5498\Test, 1 test) +Test Suite Finished (CLI Arguments, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/regression/5498/Test.php b/tests/end-to-end/regression/5498/Test.php new file mode 100644 index 00000000000..db92e41ada8 --- /dev/null +++ b/tests/end-to-end/regression/5498/Test.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5498; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; + +final class Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } + + #[Before] + protected function before(): void + { + } + + #[After] + protected function after(): void + { + } +} diff --git a/tests/end-to-end/regression/5498/TestCase.php b/tests/end-to-end/regression/5498/TestCase.php new file mode 100644 index 00000000000..b577abf152f --- /dev/null +++ b/tests/end-to-end/regression/5498/TestCase.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5498; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; + +abstract class TestCase extends \PHPUnit\Framework\TestCase +{ + #[Before] + protected function parentBefore(): void + { + } + + #[After] + protected function parentAfter(): void + { + } +} diff --git a/tests/end-to-end/regression/5561.phpt b/tests/end-to-end/regression/5561.phpt new file mode 100644 index 00000000000..5c033944a5e --- /dev/null +++ b/tests/end-to-end/regression/5561.phpt @@ -0,0 +1,26 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5561 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + PHPUnit\TestFixture\Issue5561\Issue5561Test::testOne%A +Failed asserting that false is true. +%A +%sIssue5561Test.php:18 + + + diff --git a/tests/end-to-end/regression/5561/Issue5561Test.php b/tests/end-to-end/regression/5561/Issue5561Test.php new file mode 100644 index 00000000000..b81c334dfb7 --- /dev/null +++ b/tests/end-to-end/regression/5561/Issue5561Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5561; + +use PHPUnit\Framework\TestCase; + +final class Issue5561Test extends TestCase +{ + protected function setUp(): void + { + $this->assertTrue(false); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5567.phpt b/tests/end-to-end/regression/5567.phpt new file mode 100644 index 00000000000..abcd46020ff --- /dev/null +++ b/tests/end-to-end/regression/5567.phpt @@ -0,0 +1,32 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5567 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s MB + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue5567\Issue5567Test::testAnythingThatFailsWithRecursiveArray +Failed asserting that Array &0 [ + 'self' => Array &1 [ + 'self' => Array &1, + ], +] is false. + +%sIssue5567Test.php:%d + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/5567/Issue5567Test.php b/tests/end-to-end/regression/5567/Issue5567Test.php new file mode 100644 index 00000000000..cbbcec219ad --- /dev/null +++ b/tests/end-to-end/regression/5567/Issue5567Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5567; + +use PHPUnit\Framework\TestCase; + +final class Issue5567Test extends TestCase +{ + public function testAnythingThatFailsWithRecursiveArray(): void + { + $array = []; + $array['self'] = &$array; + + $this->assertFalse($array); + } +} diff --git a/tests/end-to-end/regression/5574.phpt b/tests/end-to-end/regression/5574.phpt new file mode 100644 index 00000000000..bb1718ffb44 --- /dev/null +++ b/tests/end-to-end/regression/5574.phpt @@ -0,0 +1,33 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5574 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s MB + +There was 1 error: + +1) PHPUnit\TestFixture\Issue5574\Issue5574Test::testThrownWrappedThrowablesOutputsCorrectStackTraceForEach +Exception: My exception + +%sIssue5574Test.php:22 + +Caused by +Error: Inner Exception + +%sIssue5574Test.php:21 + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/5574/Issue5574Test.php b/tests/end-to-end/regression/5574/Issue5574Test.php new file mode 100644 index 00000000000..4fde4db842e --- /dev/null +++ b/tests/end-to-end/regression/5574/Issue5574Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5574; + +use Error; +use Exception; +use PHPUnit\Framework\TestCase; + +final class Issue5574Test extends TestCase +{ + public function testThrownWrappedThrowablesOutputsCorrectStackTraceForEach(): void + { + $innerException = new Error('Inner Exception'); + $outerException = new Exception('My exception', 0, $innerException); + + throw $outerException; + } +} diff --git a/tests/end-to-end/regression/5592-process-isolation-events.phpt b/tests/end-to-end/regression/5592-process-isolation-events.phpt new file mode 100644 index 00000000000..f18e32dea04 --- /dev/null +++ b/tests/end-to-end/regression/5592-process-isolation-events.phpt @@ -0,0 +1,73 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/5592 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (6 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (6 tests) +Test Suite Started (PHPUnit\TestFixture\Issue5592TestIsolation, 6 tests) +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedErrorHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedErrorHandler) +Test Passed (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedErrorHandler) +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedErrorHandler) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedErrorHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedErrorHandler) +Test Failed (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedErrorHandler) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedErrorHandler) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler) +Test Failed (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler) +Failed asserting that false is true. +Test Considered Risky (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler) +Test code or tested code removed error handlers other than its own +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedExceptionHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedExceptionHandler) +Test Passed (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedExceptionHandler) +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedAndRemovedExceptionHandler) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedExceptionHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedExceptionHandler) +Test Failed (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedExceptionHandler) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testAddedExceptionHandler) +Child Process Finished +Child Process Started +Test Preparation Started (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedExceptionHandler) +Test Prepared (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedExceptionHandler) +Test Failed (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedExceptionHandler) +Failed asserting that false is true. +Test Finished (PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedExceptionHandler) +Child Process Finished +Test Suite Finished (PHPUnit\TestFixture\Issue5592TestIsolation, 6 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 1) diff --git a/tests/end-to-end/regression/5592-process-isolation.phpt b/tests/end-to-end/regression/5592-process-isolation.phpt new file mode 100644 index 00000000000..695950f3bf9 --- /dev/null +++ b/tests/end-to-end/regression/5592-process-isolation.phpt @@ -0,0 +1,59 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/5592 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.FF.FF 6 / 6 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Issue5592TestIsolation::testAddedErrorHandler +Failed asserting that false is true. + +%sIssue5592TestIsolation.php:%i + +2) PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler +Failed asserting that false is true. + +%sIssue5592TestIsolation.php:%i + +3) PHPUnit\TestFixture\Issue5592TestIsolation::testAddedExceptionHandler +Failed asserting that false is true. + +%sIssue5592TestIsolation.php:%i + +4) PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedExceptionHandler +Failed asserting that false is true. + +%sIssue5592TestIsolation.php:%i + +-- + +There was 1 risky test: + +1) PHPUnit\TestFixture\Issue5592TestIsolation::testRemovedErrorHandler +Test code or tested code removed error handlers other than its own + +%sIssue5592TestIsolation.php:%i + +FAILURES! +Tests: 6, Assertions: 10, Failures: 4, Risky: 1. diff --git a/tests/end-to-end/regression/5592.phpt b/tests/end-to-end/regression/5592.phpt new file mode 100644 index 00000000000..c689580f3cf --- /dev/null +++ b/tests/end-to-end/regression/5592.phpt @@ -0,0 +1,73 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/5592 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.FF.FF 6 / 6 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Issue5592Test::testAddedErrorHandler +Failed asserting that false is true. + +%sIssue5592Test.php:%i + +2) PHPUnit\TestFixture\Issue5592Test::testRemovedErrorHandler +Failed asserting that false is true. + +%sIssue5592Test.php:%i + +3) PHPUnit\TestFixture\Issue5592Test::testAddedExceptionHandler +Failed asserting that false is true. + +%sIssue5592Test.php:%i + +4) PHPUnit\TestFixture\Issue5592Test::testRemovedExceptionHandler +Failed asserting that false is true. + +%sIssue5592Test.php:%i + +-- + +There were 4 risky tests: + +1) PHPUnit\TestFixture\Issue5592Test::testAddedErrorHandler +Test code or tested code did not remove its own error handlers + +%sIssue5592Test.php:%i + +2) PHPUnit\TestFixture\Issue5592Test::testRemovedErrorHandler +Test code or tested code removed error handlers other than its own + +%sIssue5592Test.php:%i + +3) PHPUnit\TestFixture\Issue5592Test::testAddedExceptionHandler +Test code or tested code did not remove its own exception handlers + +%sIssue5592Test.php:%i + +4) PHPUnit\TestFixture\Issue5592Test::testRemovedExceptionHandler +Test code or tested code removed exception handlers other than its own + +%sIssue5592Test.php:%i + +FAILURES! +Tests: 6, Assertions: 10, Failures: 4, Risky: 4. diff --git a/tests/end-to-end/regression/5592/Issue5592Test.php b/tests/end-to-end/regression/5592/Issue5592Test.php new file mode 100644 index 00000000000..1499e24f27e --- /dev/null +++ b/tests/end-to-end/regression/5592/Issue5592Test.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function restore_error_handler; +use function restore_exception_handler; +use function set_error_handler; +use function set_exception_handler; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\ErrorHandler; +use Throwable; + +class Issue5592Test extends TestCase +{ + public function testAddedAndRemovedErrorHandler(): void + { + $previous = set_error_handler([$this, 'addedAndRemovedErrorHandler']); + restore_error_handler(); + + $this->assertInstanceOf(ErrorHandler::class, $previous); + $this->assertTrue(true); + } + + public function testAddedErrorHandler(): void + { + $previous = set_error_handler([$this, 'addedErrorHandler']); + + $this->assertInstanceOf(ErrorHandler::class, $previous); + $this->assertTrue(false); + } + + public function testRemovedErrorHandler(): void + { + restore_error_handler(); + $this->assertTrue(false); + } + + public function testAddedAndRemovedExceptionHandler(): void + { + $previous = set_exception_handler([$this, 'addedAndRemovedExceptionHandler']); + restore_exception_handler(); + + $this->assertSame('global5592ExceptionHandler', $previous); + $this->assertTrue(true); + } + + public function testAddedExceptionHandler(): void + { + $previous = set_exception_handler([$this, 'addedExceptionHandler']); + + $this->assertSame('global5592ExceptionHandler', $previous); + $this->assertTrue(false); + } + + public function testRemovedExceptionHandler(): void + { + restore_exception_handler(); + $this->assertTrue(false); + } + + public function addedAndRemovedErrorHandler($errno, $errstr, $errfile, $errline): bool + { + return false; + } + + public function addedErrorHandler($errno, $errstr, $errfile, $errline): bool + { + return false; + } + + public function addedAndRemovedExceptionHandler(Throwable $exception): void + { + } + + public function addedExceptionHandler(Throwable $exception): void + { + } +} diff --git a/tests/end-to-end/regression/5592/Issue5592TestIsolation.php b/tests/end-to-end/regression/5592/Issue5592TestIsolation.php new file mode 100644 index 00000000000..81e6d286d9b --- /dev/null +++ b/tests/end-to-end/regression/5592/Issue5592TestIsolation.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use function restore_error_handler; +use function restore_exception_handler; +use function set_error_handler; +use function set_exception_handler; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\ErrorHandler; +use Throwable; + +class Issue5592TestIsolation extends TestCase +{ + public function testAddedAndRemovedErrorHandler(): void + { + $previous = set_error_handler([$this, 'addedAndRemovedErrorHandler']); + restore_error_handler(); + + $this->assertInstanceOf(ErrorHandler::class, $previous); + $this->assertTrue(true); + } + + public function testAddedErrorHandler(): void + { + $previous = set_error_handler([$this, 'addedErrorHandler']); + + $this->assertInstanceOf(ErrorHandler::class, $previous); + $this->assertTrue(false); + } + + public function testRemovedErrorHandler(): void + { + restore_error_handler(); + $this->assertTrue(false); + } + + public function testAddedAndRemovedExceptionHandler(): void + { + $previous = set_exception_handler([$this, 'addedAndRemovedExceptionHandler']); + restore_exception_handler(); + + $this->assertNull($previous); + $this->assertTrue(true); + } + + public function testAddedExceptionHandler(): void + { + $previous = set_exception_handler([$this, 'addedExceptionHandler']); + + $this->assertNull($previous); + $this->assertTrue(false); + } + + public function testRemovedExceptionHandler(): void + { + restore_exception_handler(); + $this->assertTrue(false); + } + + public function addedAndRemovedErrorHandler($errno, $errstr, $errfile, $errline): bool + { + return false; + } + + public function addedErrorHandler($errno, $errstr, $errfile, $errline): bool + { + return false; + } + + public function addedAndRemovedExceptionHandler(Throwable $exception): void + { + } + + public function addedExceptionHandler(Throwable $exception): void + { + } +} diff --git a/tests/end-to-end/regression/5614.phpt b/tests/end-to-end/regression/5614.phpt new file mode 100644 index 00000000000..ac69cf4de35 --- /dev/null +++ b/tests/end-to-end/regression/5614.phpt @@ -0,0 +1,20 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5614 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5614/Issue5614Test.php b/tests/end-to-end/regression/5614/Issue5614Test.php new file mode 100644 index 00000000000..4866aeb99ad --- /dev/null +++ b/tests/end-to-end/regression/5614/Issue5614Test.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5614; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue5614Test extends TestCase +{ + public static function provideRecursiveArray(): iterable + { + $array = []; + $array[0] = &$array; + + yield [$array]; + } + + #[DataProvider('provideRecursiveArray')] + public function testRecursiveArray(array $array): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5616.phpt b/tests/end-to-end/regression/5616.phpt new file mode 100644 index 00000000000..506ced27b6c --- /dev/null +++ b/tests/end-to-end/regression/5616.phpt @@ -0,0 +1,28 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5616 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s MB + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue5616\Issue5616Test::testOne#0 with data (1, '2', 3.0, true) +Failed asserting that false is true. + +%sIssue5616Test.php:%d + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/5616/Issue5616Test.php b/tests/end-to-end/regression/5616/Issue5616Test.php new file mode 100644 index 00000000000..48f670ea436 --- /dev/null +++ b/tests/end-to-end/regression/5616/Issue5616Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5616; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue5616Test extends TestCase +{ + public static function provider(): array + { + return [ + [1, '2', 3.0, true], + ]; + } + + #[DataProvider('provider')] + public function testOne(int $a, string $b, float $c, bool $d): void + { + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/5760.phpt b/tests/end-to-end/regression/5760.phpt new file mode 100644 index 00000000000..03cf2c61358 --- /dev/null +++ b/tests/end-to-end/regression/5760.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5760 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +Issue5760 (PHPUnit\TestFixture\Issue5760\Issue5760) + ✘ One + │ + │ Exception: message + │ + │ %s:19 + │ + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/5760/Issue5760Test.php b/tests/end-to-end/regression/5760/Issue5760Test.php new file mode 100644 index 00000000000..b4babfb9f11 --- /dev/null +++ b/tests/end-to-end/regression/5760/Issue5760Test.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5760; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class Issue5760Test extends TestCase +{ + protected function setUp(): void + { + throw new Exception('message'); + } + + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/regression/5764/5764.phpt b/tests/end-to-end/regression/5764/5764.phpt new file mode 100644 index 00000000000..5c56917a27e --- /dev/null +++ b/tests/end-to-end/regression/5764/5764.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5764 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\Issue5764\Issue5764Test". + +No tests executed! diff --git a/tests/end-to-end/regression/5764/error-handler.php b/tests/end-to-end/regression/5764/error-handler.php new file mode 100644 index 00000000000..0c245d77722 --- /dev/null +++ b/tests/end-to-end/regression/5764/error-handler.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +\set_error_handler(static function (int $err_lvl, string $err_msg, string $err_file, int $err_line): bool +{ + throw new ErrorException($err_msg, 0, $err_lvl, $err_file, $err_line); +}); diff --git a/tests/end-to-end/regression/5764/phpunit.xml b/tests/end-to-end/regression/5764/phpunit.xml new file mode 100644 index 00000000000..e3f2c4b08fd --- /dev/null +++ b/tests/end-to-end/regression/5764/phpunit.xml @@ -0,0 +1,11 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/5764/tests/Issue5764Test.php b/tests/end-to-end/regression/5764/tests/Issue5764Test.php new file mode 100644 index 00000000000..c1d2614fd43 --- /dev/null +++ b/tests/end-to-end/regression/5764/tests/Issue5764Test.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5764; + +use PHPUnit\Framework\TestCase; + +final class Issue5764Test extends TestCase +{ +} diff --git a/tests/end-to-end/regression/5771.phpt b/tests/end-to-end/regression/5771.phpt new file mode 100644 index 00000000000..c9e6c1a972a --- /dev/null +++ b/tests/end-to-end/regression/5771.phpt @@ -0,0 +1,24 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5771 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + PHPUnit\TestFixture\Issue5771\Issue5771Test::testOne%A +Test was run in child process and ended unexpectedly + + + diff --git a/tests/end-to-end/regression/5771/Issue5771Test.php b/tests/end-to-end/regression/5771/Issue5771Test.php new file mode 100644 index 00000000000..33147cdfac6 --- /dev/null +++ b/tests/end-to-end/regression/5771/Issue5771Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5771; + +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class Issue5771Test extends TestCase +{ + #[RunInSeparateProcess] + public function testOne(): void + { + exit; + } +} diff --git a/tests/end-to-end/regression/5807.phpt b/tests/end-to-end/regression/5807.phpt new file mode 100644 index 00000000000..ed2f9e6a93d --- /dev/null +++ b/tests/end-to-end/regression/5807.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5807 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/5807/phpunit.xml b/tests/end-to-end/regression/5807/phpunit.xml new file mode 100644 index 00000000000..c298a260cbd --- /dev/null +++ b/tests/end-to-end/regression/5807/phpunit.xml @@ -0,0 +1,17 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/regression/5807/src/Greeter.php b/tests/end-to-end/regression/5807/src/Greeter.php new file mode 100644 index 00000000000..afa3b4afb53 --- /dev/null +++ b/tests/end-to-end/regression/5807/src/Greeter.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5807; + +final class Greeter +{ + public function greet(): string + { + return 'Hello world!'; + } +} diff --git a/tests/end-to-end/regression/5807/tests/GreeterTest.php b/tests/end-to-end/regression/5807/tests/GreeterTest.php new file mode 100644 index 00000000000..b748b91c801 --- /dev/null +++ b/tests/end-to-end/regression/5807/tests/GreeterTest.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5807; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\TestCase; + +#[CoversMethod(Greeter::class, 'greet')] +final class GreeterTest extends TestCase +{ + public function testGreets(): void + { + $this->assertSame('Hello world!', (new Greeter)->greet()); + } +} diff --git a/tests/end-to-end/regression/581.phpt b/tests/end-to-end/regression/581.phpt new file mode 100644 index 00000000000..45048a55862 --- /dev/null +++ b/tests/end-to-end/regression/581.phpt @@ -0,0 +1,40 @@ +--TEST-- +GH-581: PHPUnit_Util_Type::export adds extra newlines in Windows +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue581Test::testExportingObjectsDoesNotBreakWindowsLineFeeds +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + 1 => 2 + 2 => 'Test\r\n' + 3 => 4 +- 4 => 5 ++ 4 => 1 + 5 => 6 + 6 => 7 + 7 => 8 + ) + +%s:%i + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/581/Issue581Test.php b/tests/end-to-end/regression/581/Issue581Test.php new file mode 100644 index 00000000000..e150e89d7a2 --- /dev/null +++ b/tests/end-to-end/regression/581/Issue581Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue581Test extends TestCase +{ + public function testExportingObjectsDoesNotBreakWindowsLineFeeds(): void + { + $this->assertEquals( + (object) [1, 2, "Test\r\n", 4, 5, 6, 7, 8], + (object) [1, 2, "Test\r\n", 4, 1, 6, 7, 8], + ); + } +} diff --git a/tests/end-to-end/regression/5822.phpt b/tests/end-to-end/regression/5822.phpt new file mode 100644 index 00000000000..2440499ae14 --- /dev/null +++ b/tests/end-to-end/regression/5822.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/pull/5592 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +D 1 / 1 (100%) + +Time: %s, Memory: %s + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/end-to-end/regression/5822/phpunit.xml b/tests/end-to-end/regression/5822/phpunit.xml new file mode 100644 index 00000000000..867b70dc246 --- /dev/null +++ b/tests/end-to-end/regression/5822/phpunit.xml @@ -0,0 +1,15 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/regression/5822/src/.keep b/tests/end-to-end/regression/5822/src/.keep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/end-to-end/regression/5822/tests/Issue5822Test.php b/tests/end-to-end/regression/5822/tests/Issue5822Test.php new file mode 100644 index 00000000000..7e746ffb447 --- /dev/null +++ b/tests/end-to-end/regression/5822/tests/Issue5822Test.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5822; + +use const E_USER_DEPRECATED; +use function call_user_func; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Issue5822Test extends TestCase +{ + public function testDebugBacktrace(): void + { + $this->callUserFuncExample(); + $this->assertTrue(true); + } + + private function callUserFuncExample(): void + { + call_user_func([$this, 'exampleCallback']); + } + + private function exampleCallback(): void + { + trigger_error('My Deprecation Error', E_USER_DEPRECATED); + } +} diff --git a/tests/end-to-end/regression/5844.phpt b/tests/end-to-end/regression/5844.phpt new file mode 100644 index 00000000000..a4907d37366 --- /dev/null +++ b/tests/end-to-end/regression/5844.phpt @@ -0,0 +1,34 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5844 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%s5844%sbootstrap.php) +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5844\Issue5844Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5844\Issue5844Test::testOne) +Test Considered Risky (PHPUnit\TestFixture\Issue5844\Issue5844Test::testOne) +At least one error handler is not callable outside the scope it was registered in +Test Prepared (PHPUnit\TestFixture\Issue5844\Issue5844Test::testOne) +Test Passed (PHPUnit\TestFixture\Issue5844\Issue5844Test::testOne) +Test Finished (PHPUnit\TestFixture\Issue5844\Issue5844Test::testOne) +Test Suite Finished (PHPUnit\TestFixture\Issue5844\Issue5844Test, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/regression/5844/Issue5844Test.php b/tests/end-to-end/regression/5844/Issue5844Test.php new file mode 100644 index 00000000000..5fe84a20279 --- /dev/null +++ b/tests/end-to-end/regression/5844/Issue5844Test.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5844; + +use PHPUnit\Framework\TestCase; + +final class Issue5844Test extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5844/bootstrap.php b/tests/end-to-end/regression/5844/bootstrap.php new file mode 100644 index 00000000000..47bdc13d701 --- /dev/null +++ b/tests/end-to-end/regression/5844/bootstrap.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5844; + +use function set_error_handler; + +final class CustomErrorHandler +{ + public function __construct() + { + set_error_handler([$this, 'handleError']); + } + + private function handleError(): void + { + } +} + +new CustomErrorHandler; diff --git a/tests/end-to-end/regression/5875.phpt b/tests/end-to-end/regression/5875.phpt new file mode 100644 index 00000000000..67b658c9044 --- /dev/null +++ b/tests/end-to-end/regression/5875.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5875 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..... 5 / 5 (100%) + +Time: %s, Memory: %s + +OK (5 tests, 5 assertions) diff --git a/tests/end-to-end/regression/5875/Issue5875Test.php b/tests/end-to-end/regression/5875/Issue5875Test.php new file mode 100644 index 00000000000..3940e8cf51d --- /dev/null +++ b/tests/end-to-end/regression/5875/Issue5875Test.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5875; + +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\TestCase; + +final class Issue5875Test extends TestCase +{ + private static int $destructsDone = 0; + + public function __destruct() + { + self::$destructsDone++; + } + + public function testFirstTest(): void + { + $this->assertSame(0, self::$destructsDone); + } + + #[Depends('testFirstTest')] + public function testSecondTest(): void + { + $this->assertSame(1, self::$destructsDone); + } + + #[Depends('testSecondTest')] + #[TestWith([2])] + #[TestWith([3])] + #[TestWith([4])] + public function testThirdTestWhichUsesDataProvider($numberOfTestsBeforeThisOne): void + { + $this->assertSame($numberOfTestsBeforeThisOne, self::$destructsDone); + } +} diff --git a/tests/end-to-end/regression/5884.phpt b/tests/end-to-end/regression/5884.phpt new file mode 100644 index 00000000000..1a1105b2c01 --- /dev/null +++ b/tests/end-to-end/regression/5884.phpt @@ -0,0 +1,36 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5884 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +Time: %s, Memory: %s + +Foo (PHPUnit\TestFixture\Issue5884\Foo) + ⚠ Expect user deprecation message n o t ignoring deprecations + ✔ Expect user deprecation message a n d ignoring deprecations + ✔ Pcre has utf 8 support + ✔ Stream to non writable file with p h p unit error handler + ✔ Stream to non writable file without p h p unit error handler + ✔ Stream to invalid file + +1 test triggered 1 deprecation: + +1) %sFooTest.php:31 +foo + +OK, but there were issues! +Tests: 6, Assertions: 7, Deprecations: 1. diff --git a/tests/end-to-end/regression/5884/phpunit.xml b/tests/end-to-end/regression/5884/phpunit.xml new file mode 100644 index 00000000000..517ddd75e48 --- /dev/null +++ b/tests/end-to-end/regression/5884/phpunit.xml @@ -0,0 +1,21 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/5884/src/Foo.php b/tests/end-to-end/regression/5884/src/Foo.php new file mode 100644 index 00000000000..6f973bc4fd7 --- /dev/null +++ b/tests/end-to-end/regression/5884/src/Foo.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5884; + +use function error_get_last; +use function fopen; +use function is_array; +use function preg_match; +use Exception; + +final class Foo +{ + public static function pcreHasUtf8Support() + { + // This regex deliberately has a compile error to demonstrate the issue. + return (bool) @preg_match('/^.[/u', 'a'); + } + + public static function openFile($filename): void + { + // Silenced the PHP native warning in favour of throwing an exception. + $download = @fopen($filename, 'wb'); + + if ($download === false) { + $error = error_get_last(); + + if (!is_array($error)) { + // Shouldn't be possible, but can happen in test situations. + $error = ['message' => 'Failed to open stream']; + } + + throw new Exception($error['message']); + } + } +} diff --git a/tests/end-to-end/regression/5884/tests/FooTest.php b/tests/end-to-end/regression/5884/tests/FooTest.php new file mode 100644 index 00000000000..a1a5ce0213a --- /dev/null +++ b/tests/end-to-end/regression/5884/tests/FooTest.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5884; + +use const E_USER_DEPRECATED; +use function chmod; +use function file_get_contents; +use function file_put_contents; +use function sys_get_temp_dir; +use function tempnam; +use function trigger_error; +use function unlink; +use Exception; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Framework\TestCase; + +final class FooTest extends TestCase +{ + public function testExpectUserDeprecationMessageNOTIgnoringDeprecations(): void + { + $this->expectUserDeprecationMessage('foo'); + + trigger_error('foo', E_USER_DEPRECATED); + } + + #[IgnoreDeprecations] + public function testExpectUserDeprecationMessageANDIgnoringDeprecations(): void + { + $this->expectUserDeprecationMessage('foo'); + + trigger_error('foo', E_USER_DEPRECATED); + } + + public function testPcreHasUtf8Support(): void + { + $this->assertIsBool(Foo::pcreHasUtf8Support()); + } + + public function testStreamToNonWritableFileWithPHPUnitErrorHandler(): void + { + // Create an unwritable file. + $filename = tempnam(sys_get_temp_dir(), 'RLT'); + + if (file_put_contents($filename, 'foo')) { + chmod($filename, 0o444); + } + + try { + Foo::openFile($filename); + } catch (Exception $e) { + // This "Failed to open stream" exception is expected. + } + + // Now verify the original file is unchanged. + $contents = file_get_contents($filename); + + chmod($filename, 0o755); + unlink($filename); + + $this->assertSame('foo', $contents); + } + + #[WithoutErrorHandler] + public function testStreamToNonWritableFileWithoutPHPUnitErrorHandler(): void + { + // Create an unwritable file. + $filename = tempnam(sys_get_temp_dir(), 'RLT'); + + if (file_put_contents($filename, 'foo')) { + chmod($filename, 0o444); + } + + try { + Foo::openFile($filename); + } catch (Exception $e) { + // This "Failed to open stream" exception is expected. + } + + // Now verify the original file is unchanged. + $contents = file_get_contents($filename); + + chmod($filename, 0o755); + unlink($filename); + + $this->assertSame('foo', $contents); + } + + public function testStreamToInvalidFile(): void + { + $filename = tempnam(sys_get_temp_dir(), 'RLT') . '/missing/directory'; + + $this->expectException(Exception::class); + // First character (F) can be upper or lowercase depending on PHP version. + $this->expectExceptionMessage('ailed to open stream'); + + Foo::openFile($filename); + } +} diff --git a/tests/end-to-end/regression/5891.phpt b/tests/end-to-end/regression/5891.phpt new file mode 100644 index 00000000000..f10afad8236 --- /dev/null +++ b/tests/end-to-end/regression/5891.phpt @@ -0,0 +1,20 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5891 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s MB + +OK (2 tests, 4 assertions) diff --git a/tests/end-to-end/regression/5891/Issue5891Test.php b/tests/end-to-end/regression/5891/Issue5891Test.php new file mode 100644 index 00000000000..d22c5ed846d --- /dev/null +++ b/tests/end-to-end/regression/5891/Issue5891Test.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5891; + +use PHPUnit\Framework\TestCase; + +final class Issue5891Test extends TestCase +{ + public function testVariadicParam(): void + { + $mock = $this->createMock(ArgumentList::class); + $mock + ->method('foo') + ->with($this->callback(static function (...$items): bool + { + self::assertSame([1, 2, 3], $items); + + return true; + })); + + $mock->foo(1, 2, 3); + } + + public function testTwoParametersAndVariadicParam(): void + { + $mock = $this->createMock(TwoParametersAndArgumentList::class); + $mock + ->method('foo') + ->with($this->callback(static function (...$items): bool + { + self::assertSame(['1st', '2nd', '3rd', '4th'], $items); + + return true; + })); + + $mock->foo('1st', '2nd', '3rd', '4th'); + } +} + +interface ArgumentList +{ + public function foo(int ...$items): void; +} + +interface TwoParametersAndArgumentList +{ + public function foo(string $first, string $second, string ...$rest): void; +} diff --git a/tests/end-to-end/regression/5898.phpt b/tests/end-to-end/regression/5898.phpt new file mode 100644 index 00000000000..b65a285f62d --- /dev/null +++ b/tests/end-to-end/regression/5898.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5898 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (%s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%s5898.phpt, 1 test) +Test Preparation Started (%s5898.phpt) +Test Prepared (%s5898.phpt) +Child Process Started +Child Process Finished +Test Passed (%s5898.phpt) +Test Finished (%s5898.phpt) +Test Suite Finished (%s5898.phpt, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/regression/5898/5898.phpt b/tests/end-to-end/regression/5898/5898.phpt new file mode 100644 index 00000000000..3cdf2a2d8ee --- /dev/null +++ b/tests/end-to-end/regression/5898/5898.phpt @@ -0,0 +1,7 @@ +--TEST-- +PHPT test that passes +--FILE-- +run($_SERVER['argv']); + +unlink($file); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +There were errors: + +The data provider PHPUnit\TestFixture\Issue5908\Issue5908Test::provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid +message diff --git a/tests/end-to-end/regression/5908-list-tests.phpt b/tests/end-to-end/regression/5908-list-tests.phpt new file mode 100644 index 00000000000..b83c346cfcb --- /dev/null +++ b/tests/end-to-end/regression/5908-list-tests.phpt @@ -0,0 +1,19 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5908 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +There were errors: + +The data provider PHPUnit\TestFixture\Issue5908\Issue5908Test::provider specified for PHPUnit\TestFixture\Issue5908\Issue5908Test::testOne is invalid +message diff --git a/tests/end-to-end/regression/5908/Issue5908Test.php b/tests/end-to-end/regression/5908/Issue5908Test.php new file mode 100644 index 00000000000..e3e6658d2a6 --- /dev/null +++ b/tests/end-to-end/regression/5908/Issue5908Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5908; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue5908Test extends TestCase +{ + public static function provider(): array + { + throw new Exception('message'); + } + + #[DataProvider('provider')] + public function testOne(int $value): void + { + } +} diff --git a/tests/end-to-end/regression/5943.phpt b/tests/end-to-end/regression/5943.phpt new file mode 100644 index 00000000000..6745c8946c8 --- /dev/null +++ b/tests/end-to-end/regression/5943.phpt @@ -0,0 +1,20 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5943 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Available test groups: + - bar (1 test) + - barbara (1 test) + - baz (1 test) + - foo (1 test) diff --git a/tests/end-to-end/regression/5943/phpunit.xml b/tests/end-to-end/regression/5943/phpunit.xml new file mode 100644 index 00000000000..bb66b5abc66 --- /dev/null +++ b/tests/end-to-end/regression/5943/phpunit.xml @@ -0,0 +1,11 @@ + + + + + tests/a + tests/b + + + diff --git a/tests/end-to-end/regression/5943/tests/a/OneTest.php b/tests/end-to-end/regression/5943/tests/a/OneTest.php new file mode 100644 index 00000000000..1b5ead72569 --- /dev/null +++ b/tests/end-to-end/regression/5943/tests/a/OneTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5943; + +use PHPUnit\Framework\TestCase; + +final class OneTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5943/tests/b/TwoTest.php b/tests/end-to-end/regression/5943/tests/b/TwoTest.php new file mode 100644 index 00000000000..6479eacece7 --- /dev/null +++ b/tests/end-to-end/regression/5943/tests/b/TwoTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5943; + +use PHPUnit\Framework\TestCase; + +final class TwoTest extends TestCase +{ + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5949.phpt b/tests/end-to-end/regression/5949.phpt new file mode 100644 index 00000000000..4bbe1b277d0 --- /dev/null +++ b/tests/end-to-end/regression/5949.phpt @@ -0,0 +1,41 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5949 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +........ 8 / 8 (100%) + +Time: %s, Memory: %s + +Issue5949 (PHPUnit\TestFixture\Issue5949\Issue5949) + ✔ Test 1. No dollar sign. + + ✔ Test 2. No dollar sign. + + ✔ Test 3. Dollar sign ($). + + ✔ Test 4. No dollar sign. + + ✔ Test 5. Dollar $ sign. + More text. + + ✔ Test 6. No dollar sign. + + ✔ Test 7. No dollar sign. + + ✔ Test 8. No dollar sign. + + +OK (8 tests, 8 assertions) diff --git a/tests/end-to-end/regression/5949/Issue5949Test.php b/tests/end-to-end/regression/5949/Issue5949Test.php new file mode 100644 index 00000000000..28610250275 --- /dev/null +++ b/tests/end-to-end/regression/5949/Issue5949Test.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5949; + +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +class Issue5949Test extends TestCase +{ + #[TestDox("Test 1. No dollar sign.\n")] + public function test1(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 2. No dollar sign.\n")] + public function test2(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 3. Dollar sign (\$).\n")] + public function test3(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 4. No dollar sign.\n")] + public function test4(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 5. Dollar \$ sign.\n More text.\n")] + public function test5(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 6. No dollar sign.\n")] + public function test6(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 7. No dollar sign.\n")] + public function test7(): void + { + $this->assertTrue(true); + } + + #[TestDox("Test 8. No dollar sign.\n")] + public function test8(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/5965.phpt b/tests/end-to-end/regression/5965.phpt new file mode 100644 index 00000000000..3d61438eb7b --- /dev/null +++ b/tests/end-to-end/regression/5965.phpt @@ -0,0 +1,35 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5965 +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Issue5891\Issue5965Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue5891\Issue5965Test::testOne) +Test Prepared (PHPUnit\TestFixture\Issue5891\Issue5965Test::testOne) +Test Errored (PHPUnit\TestFixture\Issue5891\Issue5965Test::testOne) +(exception code: HY000) +Test Finished (PHPUnit\TestFixture\Issue5891\Issue5965Test::testOne) +Test Suite Finished (PHPUnit\TestFixture\Issue5891\Issue5965Test, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/regression/5965/Issue5965Test.php b/tests/end-to-end/regression/5965/Issue5965Test.php new file mode 100644 index 00000000000..2345a1fccee --- /dev/null +++ b/tests/end-to-end/regression/5965/Issue5965Test.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5891; + +use IteratorAggregate; +use PDOException; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\TestCase; +use ReflectionClass; +use Traversable; + +#[RequiresPhpExtension('pdo')] +final class Issue5965Test extends TestCase +{ + public function testOne(): void + { + $exception = new PDOException; + $reflector = new ReflectionClass($exception); + + $property = $reflector->getProperty('code'); + $property->setValue($exception, 'HY000'); + + $this->assertIsString($exception->getCode()); + + $iterator = new class($exception) implements IteratorAggregate + { + public PDOException $exception; + + public function __construct($exception) + { + $this->exception = $exception; + } + + public function getIterator(): Traversable + { + throw $this->exception; + } + }; + + $this->assertCount(0, $iterator); + } +} diff --git a/tests/end-to-end/regression/5976.phpt b/tests/end-to-end/regression/5976.phpt new file mode 100644 index 00000000000..66d70c84127 --- /dev/null +++ b/tests/end-to-end/regression/5976.phpt @@ -0,0 +1,30 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5976 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +These before-first-test methods errored: + +1) PHPUnit\TestFixture\Issue5967\Issue5976Test::setUpBeforeClass +Exception: message + +%sIssue5976Test.php:%d + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/5976/Issue5976Test.php b/tests/end-to-end/regression/5976/Issue5976Test.php new file mode 100644 index 00000000000..adbae81ecc4 --- /dev/null +++ b/tests/end-to-end/regression/5976/Issue5976Test.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue5967; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class Issue5976Test extends TestCase +{ + /** + * @throws Exception + */ + public static function setUpBeforeClass(): void + { + throw new Exception('message'); + } + + public function testOne(): void + { + } +} diff --git a/tests/end-to-end/regression/5991.phpt b/tests/end-to-end/regression/5991.phpt new file mode 100644 index 00000000000..d70be538ffc --- /dev/null +++ b/tests/end-to-end/regression/5991.phpt @@ -0,0 +1,28 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/5991 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) SKIPIF section triggered a parse error: +Parse error: Unmatched '}' in Standard input code on line 3 + + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/end-to-end/regression/6094.phpt b/tests/end-to-end/regression/6094.phpt new file mode 100644 index 00000000000..d90631a65c6 --- /dev/null +++ b/tests/end-to-end/regression/6094.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6094 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\Issue6094\Issue6094Test +Exception: message + +%sIssue6094Test.php:19 + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/regression/6094/Issue6094Test.php b/tests/end-to-end/regression/6094/Issue6094Test.php new file mode 100644 index 00000000000..c213f926373 --- /dev/null +++ b/tests/end-to-end/regression/6094/Issue6094Test.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6094; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class Issue6094Test extends TestCase +{ + public static function tearDownAfterClass(): void + { + throw new Exception('message'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6095.phpt b/tests/end-to-end/regression/6095.phpt new file mode 100644 index 00000000000..33b0898e028 --- /dev/null +++ b/tests/end-to-end/regression/6095.phpt @@ -0,0 +1,29 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6095 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue6095\Issue6095Test::testOne +PHPUnit\TestFixture\MockObject\AnInterface::doSomething(): bool was not expected to be called more than once. + +%sIssue6095Test.php:26 + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/6095/Issue6095Test.php b/tests/end-to-end/regression/6095/Issue6095Test.php new file mode 100644 index 00000000000..9c737beaca1 --- /dev/null +++ b/tests/end-to-end/regression/6095/Issue6095Test.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6095; + +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; + +final class Issue6095Test extends TestCase +{ + public function testOne(): void + { + $mock = $this->createMock(AnInterface::class); + + $mock + ->expects($this->once()) + ->method('doSomething'); + + $mock->doSomething(); + $mock->doSomething(); + } +} diff --git a/tests/end-to-end/regression/6098.phpt b/tests/end-to-end/regression/6098.phpt new file mode 100644 index 00000000000..400cca6ba30 --- /dev/null +++ b/tests/end-to-end/regression/6098.phpt @@ -0,0 +1,23 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6098 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + output + + + diff --git a/tests/end-to-end/regression/6098/Issue6098Test.php b/tests/end-to-end/regression/6098/Issue6098Test.php new file mode 100644 index 00000000000..4ef2f374411 --- /dev/null +++ b/tests/end-to-end/regression/6098/Issue6098Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6098; + +use PHPUnit\Framework\TestCase; + +final class Issue6098Test extends TestCase +{ + public function testOne(): void + { + print 'output'; + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6100.phpt b/tests/end-to-end/regression/6100.phpt new file mode 100644 index 00000000000..f4be3532fb7 --- /dev/null +++ b/tests/end-to-end/regression/6100.phpt @@ -0,0 +1,37 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6100 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (PHPUnit\TestFixture\Issue6100\Issue6100Test, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\Issue6100\Issue6100Test::testOne) +Test Prepared (PHPUnit\TestFixture\Issue6100\Issue6100Test::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\Issue6100\Issue6100Test::testOne, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in %s:%d +test +Test Passed (PHPUnit\TestFixture\Issue6100\Issue6100Test::testOne) +Test Finished (PHPUnit\TestFixture\Issue6100\Issue6100Test::testOne) +Test Preparation Started (PHPUnit\TestFixture\Issue6100\Issue6100Test::testTwo) +Test Prepared (PHPUnit\TestFixture\Issue6100\Issue6100Test::testTwo) +Test Passed (PHPUnit\TestFixture\Issue6100\Issue6100Test::testTwo) +Test Finished (PHPUnit\TestFixture\Issue6100\Issue6100Test::testTwo) +Test Suite Finished (PHPUnit\TestFixture\Issue6100\Issue6100Test, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/regression/6100/Issue6100Test.php b/tests/end-to-end/regression/6100/Issue6100Test.php new file mode 100644 index 00000000000..7432d150e17 --- /dev/null +++ b/tests/end-to-end/regression/6100/Issue6100Test.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6100; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class Issue6100Test extends TestCase +{ + public function testOne(): void + { + @trigger_error('test', E_USER_DEPRECATED); + + $this->assertTrue(true); + } + + public function testTwo(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6102-process-isolation-via-attribute.phpt b/tests/end-to-end/regression/6102-process-isolation-via-attribute.phpt new file mode 100644 index 00000000000..df41f69a556 --- /dev/null +++ b/tests/end-to-end/regression/6102-process-isolation-via-attribute.phpt @@ -0,0 +1,38 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6102 +--XFAIL-- +https://github.com/sebastianbergmann/phpunit/issues/6102 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..FF..FF 8 / 8 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message "message" was not triggered + +2) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered +Expected deprecation with message "message" was not triggered + +3) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +4) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureInIsolationTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +FAILURES! +Tests: 8, Assertions: 10, Failures: 4. diff --git a/tests/end-to-end/regression/6102-process-isolation-via-cli-option.phpt b/tests/end-to-end/regression/6102-process-isolation-via-cli-option.phpt new file mode 100644 index 00000000000..5b6c346b8f4 --- /dev/null +++ b/tests/end-to-end/regression/6102-process-isolation-via-cli-option.phpt @@ -0,0 +1,39 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6102 +--XFAIL-- +https://github.com/sebastianbergmann/phpunit/issues/6102 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +..FF..FF 8 / 8 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnExactDeprecationMessageWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message "message" was not triggered + +2) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnExactDeprecationMessageWorksWhenUnexpectedDeprecationIsTriggered +Expected deprecation with message "message" was not triggered + +3) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenExpectedDeprecationIsNotTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +4) PHPUnit\TestFixture\Event\TestForDeprecatedFeatureTest::testExpectationOnDeprecationMessageMatchingRegularExpressionWorksWhenUnepectedDeprecationIsTriggered +Expected deprecation with message matching regular expression "/message/" was not triggered + +FAILURES! +Tests: 8, Assertions: 10, Failures: 4. diff --git a/tests/end-to-end/regression/6103.phpt b/tests/end-to-end/regression/6103.phpt new file mode 100644 index 00000000000..cbebf70c862 --- /dev/null +++ b/tests/end-to-end/regression/6103.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6103 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +*. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/6103/Issue6103Test.php b/tests/end-to-end/regression/6103/Issue6103Test.php new file mode 100644 index 00000000000..be6488a2644 --- /dev/null +++ b/tests/end-to-end/regression/6103/Issue6103Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6103; + +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +final class Issue6103Test extends TestCase +{ + #[RunInSeparateProcess] + public function testOne(): void + { + print '*'; + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6105.phpt b/tests/end-to-end/regression/6105.phpt new file mode 100644 index 00000000000..df4806878be --- /dev/null +++ b/tests/end-to-end/regression/6105.phpt @@ -0,0 +1,41 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6105 +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 3 assertions) diff --git a/tests/end-to-end/regression/6105/IssueTest6105.php b/tests/end-to-end/regression/6105/IssueTest6105.php new file mode 100644 index 00000000000..b2467042fcc --- /dev/null +++ b/tests/end-to-end/regression/6105/IssueTest6105.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace IssueTest6105; + +use function header; +use function ob_get_clean; +use function ob_start; +use function xdebug_get_headers; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\TestCase; + +#[CoversNothing] +class IssueTest6105 extends TestCase +{ + public function test_1(): void + { + $this->assertTrue(true); + } + + #[RunInSeparateProcess] + #[RequiresPhpExtension('xdebug')] + public function test_case_2_check(): void + { + ob_start(); + header('X-Test: Testing'); + print 'asd'; + $content = ob_get_clean(); + + $this->assertSame('asd', $content); + $this->assertSame(['X-Test: Testing'], xdebug_get_headers()); + } +} diff --git a/tests/end-to-end/regression/6109.phpt b/tests/end-to-end/regression/6109.phpt new file mode 100644 index 00000000000..090d73c970a --- /dev/null +++ b/tests/end-to-end/regression/6109.phpt @@ -0,0 +1,23 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6109 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- + + + + + + + + diff --git a/tests/end-to-end/regression/6109/Issue6109Test.php b/tests/end-to-end/regression/6109/Issue6109Test.php new file mode 100644 index 00000000000..131ab6bdb28 --- /dev/null +++ b/tests/end-to-end/regression/6109/Issue6109Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6109; + +use PHPUnit\Framework\TestCase; + +final class Issue6109Test extends TestCase +{ + protected function setUp(): void + { + print '*'; + + $this->markTestSkipped('message'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6115.phpt b/tests/end-to-end/regression/6115.phpt new file mode 100644 index 00000000000..36342e2e6e3 --- /dev/null +++ b/tests/end-to-end/regression/6115.phpt @@ -0,0 +1,25 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6115 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +Issue6115 (PHPUnit\TestFixture\Issue6115\Issue6115) + ✔ 1 + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/6115/Issue6115Test.php b/tests/end-to-end/regression/6115/Issue6115Test.php new file mode 100644 index 00000000000..c323b05511d --- /dev/null +++ b/tests/end-to-end/regression/6115/Issue6115Test.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6115; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +enum Enumeration: int +{ + case A = 1; +} + +final class Issue6115Test extends TestCase +{ + public static function provider(): array + { + return [ + [ + Enumeration::A, + ], + ]; + } + + #[DataProvider('provider')] + #[TestDox('$enumeration')] + public function testOne(Enumeration $enumeration): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6138.phpt b/tests/end-to-end/regression/6138.phpt new file mode 100644 index 00000000000..ad8f3cb5a1f --- /dev/null +++ b/tests/end-to-end/regression/6138.phpt @@ -0,0 +1,38 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6138 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue6138\Issue6138Test::testOne +Expectation failed for method name is "m" when invoked 1 time +Parameter 0 for invocation PHPUnit\TestFixture\Issue6138\I::m(PHPUnit\TestFixture\Issue6138\C Object (...)): void does not match expected value. +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + PHPUnit\TestFixture\Issue6138\C Object ( +- 'foo' => 'bar' ++ 'foo' => 'baz' + ) + +%sIssue6138Test.php:%d + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/regression/6138/Issue6138Test.php b/tests/end-to-end/regression/6138/Issue6138Test.php new file mode 100644 index 00000000000..36fa00341ff --- /dev/null +++ b/tests/end-to-end/regression/6138/Issue6138Test.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6138; + +use PHPUnit\Framework\TestCase; + +final class C +{ + private string $foo; + + public function __construct(string $foo) + { + $this->foo = $foo; + } +} + +interface I +{ + public function m(C $c): void; +} + +final class Issue6138Test extends TestCase +{ + public function testOne(): void + { + $i = $this->createMock(I::class); + + $i->expects($this->once())->method('m')->with(new C('bar')); + + $i->m(new C('baz')); + } +} diff --git a/tests/end-to-end/regression/6142.phpt b/tests/end-to-end/regression/6142.phpt new file mode 100644 index 00000000000..52e695b40f8 --- /dev/null +++ b/tests/end-to-end/regression/6142.phpt @@ -0,0 +1,38 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6142 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue6142\Issue6142Test::testOne +Failed asserting that '{"key": false}\n +' matches JSON string "{"key": true} +". +--- Expected ++++ Actual +@@ @@ + { +- "key": true ++ "key": false + } + +%sIssue6142Test.php:%d + +FAILURES! +Tests: 1, Assertions: 7, Failures: 1. diff --git a/tests/end-to-end/regression/6142/Issue6142Test.php b/tests/end-to-end/regression/6142/Issue6142Test.php new file mode 100644 index 00000000000..246189ca935 --- /dev/null +++ b/tests/end-to-end/regression/6142/Issue6142Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6142; + +use PHPUnit\Framework\TestCase; + +final class Issue6142Test extends TestCase +{ + public function testOne(): void + { + $expected = __DIR__ . '/expected.json'; + $actual = __DIR__ . '/actual.json'; + + $this->assertJsonFileEqualsJsonFile($expected, $actual); + } +} diff --git a/tests/end-to-end/regression/6142/actual.json b/tests/end-to-end/regression/6142/actual.json new file mode 100644 index 00000000000..f96f9eb3185 --- /dev/null +++ b/tests/end-to-end/regression/6142/actual.json @@ -0,0 +1 @@ +{"key": false} diff --git a/tests/end-to-end/regression/6142/expected.json b/tests/end-to-end/regression/6142/expected.json new file mode 100644 index 00000000000..95ff2f8c32c --- /dev/null +++ b/tests/end-to-end/regression/6142/expected.json @@ -0,0 +1 @@ +{"key": true} diff --git a/tests/end-to-end/regression/6173.phpt b/tests/end-to-end/regression/6173.phpt new file mode 100644 index 00000000000..df6fce927b2 --- /dev/null +++ b/tests/end-to-end/regression/6173.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6173 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +hello, success! +.hello, fail! +F 2 / 2 (100%) + +Time: %s, Memory: %s + +There was 1 failure: + +1) PHPUnit\TestFixture\Issue6173\Issue6173Test::test_log_fail +Failed asserting that false is true. + +%sIssue6173Test.php:%d + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/regression/6173/Issue6173Test.php b/tests/end-to-end/regression/6173/Issue6173Test.php new file mode 100644 index 00000000000..87b34efb218 --- /dev/null +++ b/tests/end-to-end/regression/6173/Issue6173Test.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6173; + +use function error_log; +use PHPUnit\Framework\TestCase; + +final class Issue6173Test extends TestCase +{ + public function test_log_success(): void + { + error_log('hello, success!'); + $this->assertTrue(true); + } + + public function test_log_fail(): void + { + error_log('hello, fail!'); + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/regression/6222.phpt b/tests/end-to-end/regression/6222.phpt new file mode 100644 index 00000000000..e0c6ffc49e6 --- /dev/null +++ b/tests/end-to-end/regression/6222.phpt @@ -0,0 +1,55 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6222 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +F....FSFFS 10 / 10 (100%) + +Time: %s, Memory: %s + +There were 4 failures: + +1) PHPUnit\TestFixture\Issue6222\Issue6222Test::testOne +Failed asserting that false is true. + +%sIssue6222Test.php:%d + +2) PHPUnit\TestFixture\Issue6222\Issue6222Test::testOneCasePassing#1 with data (2) +Failed asserting that 2 is identical to 1. + +%sIssue6222Test.php:%d + +3) PHPUnit\TestFixture\Issue6222\Issue6222Test::testZeroCasesPassing#0 with data (1) +Failed asserting that 1 is identical to 3. + +%sIssue6222Test.php:%d + +4) PHPUnit\TestFixture\Issue6222\Issue6222Test::testZeroCasesPassing#1 with data (2) +Failed asserting that 2 is identical to 3. + +%sIssue6222Test.php:%d + +-- + +There were 2 skipped tests: + +1) PHPUnit\TestFixture\Issue6222\Issue6222Test::testDependingOnOneCasePassing +This test depends on "PHPUnit\TestFixture\Issue6222\Issue6222Test::testOneCasePassing" to pass + +2) PHPUnit\TestFixture\Issue6222\Issue6222Test::testDependingOnZeroCasesPassing +This test depends on "PHPUnit\TestFixture\Issue6222\Issue6222Test::testZeroCasesPassing" to pass + +FAILURES! +Tests: 10, Assertions: 8, Failures: 4, Skipped: 2. diff --git a/tests/end-to-end/regression/6222/Issue6222Test.php b/tests/end-to-end/regression/6222/Issue6222Test.php new file mode 100644 index 00000000000..d1334e71af9 --- /dev/null +++ b/tests/end-to-end/regression/6222/Issue6222Test.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6222; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +class Issue6222Test extends TestCase +{ + public static function provider(): iterable + { + yield [1]; + + yield [2]; + } + + public function testOne(): void + { + $this->assertTrue(false); + } + + #[DataProvider('provider')] + public function testTwoCasesPassing(int $x): void + { + $this->assertGreaterThan(0, $x); + } + + #[Depends('testTwoCasesPassing')] + public function testDependingOnTwoCasesPassing(): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + public function testOneCasePassing(int $x): void + { + $this->assertSame(1, $x); + } + + #[Depends('testOneCasePassing')] + public function testDependingOnOneCasePassing(): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + public function testZeroCasesPassing(int $x): void + { + $this->assertSame(3, $x); + } + + #[Depends('testZeroCasesPassing')] + public function testDependingOnZeroCasesPassing(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6234.phpt b/tests/end-to-end/regression/6234.phpt new file mode 100644 index 00000000000..ede356b99fd --- /dev/null +++ b/tests/end-to-end/regression/6234.phpt @@ -0,0 +1,17 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6234 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Fatal error: Premature end of PHP process when running PHPUnit\TestFixture\Issue6234Test::testExitWithoutProcessIsolation. diff --git a/tests/end-to-end/regression/6234/Issue6234Test.php b/tests/end-to-end/regression/6234/Issue6234Test.php new file mode 100644 index 00000000000..e21794cbc39 --- /dev/null +++ b/tests/end-to-end/regression/6234/Issue6234Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class Issue6234Test extends TestCase +{ + public function testExitWithoutProcessIsolation(): void + { + $this->assertTrue(true); + $this->assertTrue(true); + + exit(1); + } +} diff --git a/tests/end-to-end/regression/6279.phpt b/tests/end-to-end/regression/6279.phpt new file mode 100644 index 00000000000..5ceb7fa57ab --- /dev/null +++ b/tests/end-to-end/regression/6279.phpt @@ -0,0 +1,47 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6279 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.D.DD....DD. 12 / 12 (100%) + +Time: %s, Memory: %s + +5 tests triggered 5 deprecations: + +1) %sTriggersDeprecationInDataProvider1Test.php:26 +some deprecation + +Triggered by: + +* PHPUnit\TestFixture\Issue6279\TriggersDeprecationInDataProvider1Test::method2#0 + %sTriggersDeprecationInDataProvider1Test.php:48 + +* PHPUnit\TestFixture\Issue6279\TriggersDeprecationInDataProvider1Test::method4#0 + %sTriggersDeprecationInDataProvider1Test.php:61 + +2) %sTriggersDeprecationInDataProvider1Test.php:33 +first + +3) %sTriggersDeprecationInDataProvider1Test.php:34 +second + +4) %sTriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest.php:32 +some deprecation 2 + +5) %sTriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest.php:39 +some deprecation 3 + +OK, but there were issues! +Tests: 12, Assertions: 12, Deprecations: 5. diff --git a/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider1Test.php b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider1Test.php new file mode 100644 index 00000000000..2d5e6fbc7e3 --- /dev/null +++ b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider1Test.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6279; + +use const E_USER_DEPRECATED; +use const E_USER_WARNING; +use function trigger_error; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +class TriggersDeprecationInDataProvider1Test extends TestCase +{ + public static function dataProvider(): iterable + { + @trigger_error('some deprecation', E_USER_DEPRECATED); + + yield [true]; + } + + public static function dataWith2Deprecations(): iterable + { + @trigger_error('first', E_USER_DEPRECATED); + @trigger_error('second', E_USER_DEPRECATED); + @trigger_error('warning', E_USER_WARNING); + + yield [true]; + } + + #[Test] + public function method1(): void + { + $this->assertTrue(true); + } + + #[Test] + #[DataProvider('dataProvider')] + public function method2(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + public function method3(): void + { + $this->assertTrue(true); + } + + #[Test] + #[DataProvider('dataProvider')] + public function method4(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + #[DataProviderExternal(self::class, 'dataWith2Deprecations')] + public function method5(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + public function methodWithSameNameThanInAnotherTest(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider2Test.php b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider2Test.php new file mode 100644 index 00000000000..1371cad7842 --- /dev/null +++ b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProvider2Test.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6279; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +class TriggersDeprecationInDataProvider2Test extends TestCase +{ + public static function dataProvider(): iterable + { + @trigger_error('some deprecation 1', E_USER_DEPRECATED); + + yield [true]; + } + + #[Test] + #[DataProvider('dataProvider')] + #[IgnoreDeprecations] + public function methodWithSameNameThanInAnotherTest(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/regression/6279/TriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest.php b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest.php new file mode 100644 index 00000000000..1a66dcee83a --- /dev/null +++ b/tests/end-to-end/regression/6279/TriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6279; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\IgnoreDeprecations; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; + +class TriggersDeprecationInDataProviderUsingIgnoreDeprecationsTest extends TestCase +{ + public static function dataProvider1(): iterable + { + @trigger_error('some deprecation', E_USER_DEPRECATED); + + yield [true]; + } + + public static function dataProvider2(): iterable + { + @trigger_error('some deprecation 2', E_USER_DEPRECATED); + + yield [true]; + } + + public static function dataProvider3(): iterable + { + @trigger_error('some deprecation 3', E_USER_DEPRECATED); + + yield [true]; + } + + #[Test] + #[DataProvider('dataProvider1')] + #[IgnoreDeprecations] + public function someMethod1(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + #[DataProvider('dataProvider2')] + #[IgnoreDeprecations] + public function method2_1(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + #[DataProvider('dataProvider2')] + public function method2_2(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + #[DataProvider('dataProvider3')] + public function method3_1(bool $value): void + { + $this->assertTrue($value); + } + + #[Test] + #[DataProvider('dataProvider3')] + #[IgnoreDeprecations] + public function method3_2(bool $value): void + { + $this->assertTrue($value); + } +} diff --git a/tests/end-to-end/regression/6281.phpt b/tests/end-to-end/regression/6281.phpt new file mode 100644 index 00000000000..8cfc37acd2a --- /dev/null +++ b/tests/end-to-end/regression/6281.phpt @@ -0,0 +1,38 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6281 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (PHPUnit\TestFixture\Issue6281\Issue6281Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue6281\Issue6281Test::testOne) +Before Test Method Called (PHPUnit\TestFixture\Issue6281\Issue6281Test::setUp) +Before Test Method Finished: +- PHPUnit\TestFixture\Issue6281\Issue6281Test::setUp +Test Skipped (PHPUnit\TestFixture\Issue6281\Issue6281Test::testOne) +skip message +After Test Method Called (PHPUnit\TestFixture\Issue6281\Issue6281Test::tearDown) +After Test Method Errored (PHPUnit\TestFixture\Issue6281\Issue6281Test::tearDown) +exception message +After Test Method Finished: +- PHPUnit\TestFixture\Issue6281\Issue6281Test::tearDown +Test Errored (PHPUnit\TestFixture\Issue6281\Issue6281Test::testOne) +exception message +Test Suite Finished (PHPUnit\TestFixture\Issue6281\Issue6281Test, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/regression/6281/Issue6281Test.php b/tests/end-to-end/regression/6281/Issue6281Test.php new file mode 100644 index 00000000000..509437f91ac --- /dev/null +++ b/tests/end-to-end/regression/6281/Issue6281Test.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6281; + +use Exception; +use PHPUnit\Framework\TestCase; + +final class Issue6281Test extends TestCase +{ + protected function setUp(): void + { + $this->markTestSkipped('skip message'); + } + + protected function tearDown(): void + { + throw new Exception('exception message'); + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6294-display-errors-off.phpt b/tests/end-to-end/regression/6294-display-errors-off.phpt new file mode 100644 index 00000000000..3d80ec5fb4c --- /dev/null +++ b/tests/end-to-end/regression/6294-display-errors-off.phpt @@ -0,0 +1,18 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6294 +--INI-- +display_errors=0 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Fatal error: Premature end of PHPUnit's PHP process. Use display_errors=On to see the error message. diff --git a/tests/end-to-end/regression/6294-display-errors-on.phpt b/tests/end-to-end/regression/6294-display-errors-on.phpt new file mode 100644 index 00000000000..b62bd3d61ea --- /dev/null +++ b/tests/end-to-end/regression/6294-display-errors-on.phpt @@ -0,0 +1,19 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6294 +--INI-- +display_errors=1 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + + +Fatal error: Access level to PHPUnit\TestFixture\B::someFunction() must be public (as in class PHPUnit\TestFixture\A) in %sB.php on line %i%A diff --git a/tests/end-to-end/regression/6294/A.php b/tests/end-to-end/regression/6294/A.php new file mode 100644 index 00000000000..6de88993a17 --- /dev/null +++ b/tests/end-to-end/regression/6294/A.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use const PHP_EOL; + +class A +{ + public function someFunction(): void + { + print 'A::someFunction' . PHP_EOL; + } +} diff --git a/tests/end-to-end/regression/6294/B.php b/tests/end-to-end/regression/6294/B.php new file mode 100644 index 00000000000..2ec7de7bd0a --- /dev/null +++ b/tests/end-to-end/regression/6294/B.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use const PHP_EOL; + +class B extends A +{ + // incorrect access level + protected function someFunction(): void + { + parent::someFunction(); + + print 'B::someFunction' . PHP_EOL; + } +} diff --git a/tests/end-to-end/regression/6294/IssueTest6294.php b/tests/end-to-end/regression/6294/IssueTest6294.php new file mode 100644 index 00000000000..f59c79a5e2e --- /dev/null +++ b/tests/end-to-end/regression/6294/IssueTest6294.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +final class IssueTest6294 extends TestCase +{ + public function testOne(): void + { + require_once 'A.php'; + + require_once 'B.php'; + + $this->assertSame(1, 1); + } +} diff --git a/tests/end-to-end/regression/6311.phpt b/tests/end-to-end/regression/6311.phpt new file mode 100644 index 00000000000..5b71c2e7453 --- /dev/null +++ b/tests/end-to-end/regression/6311.phpt @@ -0,0 +1,27 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6311 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit test runner warning: + +1) SKIPIF section triggered a fatal error: +Warning: require(%afile.php): Failed to open stream: No such file or directory in Standard input code on line %d + +Fatal error: Uncaught Error: Failed opening required%a +%A diff --git a/tests/end-to-end/regression/6329-runner-deprecation-ignored.phpt b/tests/end-to-end/regression/6329-runner-deprecation-ignored.phpt new file mode 100644 index 00000000000..44cfb498ef7 --- /dev/null +++ b/tests/end-to-end/regression/6329-runner-deprecation-ignored.phpt @@ -0,0 +1,22 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6329 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/6329-runner-deprecation.phpt b/tests/end-to-end/regression/6329-runner-deprecation.phpt new file mode 100644 index 00000000000..e727b2c4e3e --- /dev/null +++ b/tests/end-to-end/regression/6329-runner-deprecation.phpt @@ -0,0 +1,27 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6329 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s MB + +There was 1 PHPUnit test runner deprecation: + +1) A runner deprecation! + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 1. diff --git a/tests/end-to-end/regression/6329/Issue6329DeprecationIgnoredTest.php b/tests/end-to-end/regression/6329/Issue6329DeprecationIgnoredTest.php new file mode 100644 index 00000000000..17ffa46ab2d --- /dev/null +++ b/tests/end-to-end/regression/6329/Issue6329DeprecationIgnoredTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\IgnorePhpunitDeprecations; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class Issue6329DeprecationIgnoredTest extends TestCase +{ + #[IgnorePhpunitDeprecations] + public function testOne(): void + { + EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation( + 'A runner deprecation!', + ); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6329/Issue6329DeprecationTest.php b/tests/end-to-end/regression/6329/Issue6329DeprecationTest.php new file mode 100644 index 00000000000..5a1c9d9c6d3 --- /dev/null +++ b/tests/end-to-end/regression/6329/Issue6329DeprecationTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\TestCase; + +#[RunTestsInSeparateProcesses] +final class Issue6329DeprecationTest extends TestCase +{ + public function testOne(): void + { + EventFacade::emitter()->testRunnerTriggeredPhpunitDeprecation( + 'A runner deprecation!', + ); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6366.phpt b/tests/end-to-end/regression/6366.phpt new file mode 100644 index 00000000000..98bf01d154b --- /dev/null +++ b/tests/end-to-end/regression/6366.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6366 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 0 assertions) diff --git a/tests/end-to-end/regression/6366/Issue6366Test.php b/tests/end-to-end/regression/6366/Issue6366Test.php new file mode 100644 index 00000000000..c393793f16e --- /dev/null +++ b/tests/end-to-end/regression/6366/Issue6366Test.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6366; + +use Exception; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +final class Issue6366Test extends TestCase +{ + #[DoesNotPerformAssertions] + public function testOne(): void + { + $this->createStub(Exception::class); + } +} diff --git a/tests/end-to-end/regression/6368.phpt b/tests/end-to-end/regression/6368.phpt new file mode 100644 index 00000000000..c38342083bd --- /dev/null +++ b/tests/end-to-end/regression/6368.phpt @@ -0,0 +1,36 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6368 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (%sphpunit.xml, 1 test) +Test Suite Started (default, 1 test) +Test Suite Started (PHPUnit\TestFixture\Issue6368\Issue6368Test, 1 test) +Test Preparation Started (PHPUnit\TestFixture\Issue6368\Issue6368Test::testOne) +Test Prepared (PHPUnit\TestFixture\Issue6368\Issue6368Test::testOne) +Test Runner Triggered Warning (message) +Test Triggered PHPUnit Warning (PHPUnit\TestFixture\Issue6368\Issue6368Test::testOne) +message +Test Passed (PHPUnit\TestFixture\Issue6368\Issue6368Test::testOne) +Test Finished (PHPUnit\TestFixture\Issue6368\Issue6368Test::testOne) +Test Suite Finished (PHPUnit\TestFixture\Issue6368\Issue6368Test, 1 test) +Test Suite Finished (default, 1 test) +Test Suite Finished (%sphpunit.xml, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/regression/6368/phpunit.xml b/tests/end-to-end/regression/6368/phpunit.xml new file mode 100644 index 00000000000..0a94b4d4277 --- /dev/null +++ b/tests/end-to-end/regression/6368/phpunit.xml @@ -0,0 +1,11 @@ + + + + + tests + + + diff --git a/tests/end-to-end/regression/6368/tests/Issue6368Test.php b/tests/end-to-end/regression/6368/tests/Issue6368Test.php new file mode 100644 index 00000000000..b5c97d854f5 --- /dev/null +++ b/tests/end-to-end/regression/6368/tests/Issue6368Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6368; + +use PHPUnit\Event\Facade as EventFacade; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\TestCase; + +final class Issue6368Test extends TestCase +{ + #[DoesNotPerformAssertions] + public function testOne(): void + { + EventFacade::emitter()->testRunnerTriggeredPhpunitWarning('message'); + EventFacade::emitter()->testTriggeredPhpunitWarning($this->valueObjectForEvents(), 'message'); + } +} diff --git a/tests/end-to-end/regression/6382.phpt b/tests/end-to-end/regression/6382.phpt new file mode 100644 index 00000000000..eef500862bc --- /dev/null +++ b/tests/end-to-end/regression/6382.phpt @@ -0,0 +1,19 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6382 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + + +Fatal error: Declaration of PHPUnit\TestFixture\Issue6382\Child6382::__invoke() must be compatible with PHPUnit\TestFixture\Issue6382\Ancestor6382::__invoke(): void in %sChild.php on line %d +%AFatal error: Premature end of PHP process when running PHPUnit\TestFixture\Issue6382\Issue6382Test::testExample. diff --git a/tests/end-to-end/regression/6382/Ancestor.php b/tests/end-to-end/regression/6382/Ancestor.php new file mode 100644 index 00000000000..6d26d86e1f1 --- /dev/null +++ b/tests/end-to-end/regression/6382/Ancestor.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6382; + +interface Ancestor6382 +{ + public function __invoke(): void; +} diff --git a/tests/end-to-end/regression/6382/Child.php b/tests/end-to-end/regression/6382/Child.php new file mode 100644 index 00000000000..69be671d53f --- /dev/null +++ b/tests/end-to-end/regression/6382/Child.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6382; + +interface Child6382 extends Ancestor6382 +{ + public function __invoke(); +} diff --git a/tests/end-to-end/regression/6382/Issue6382Test.php b/tests/end-to-end/regression/6382/Issue6382Test.php new file mode 100644 index 00000000000..c4d3ee1e480 --- /dev/null +++ b/tests/end-to-end/regression/6382/Issue6382Test.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6382; + +use PHPUnit\Framework\TestCase; + +class Issue6382Test extends TestCase +{ + public function testExample(): void + { + require_once __DIR__ . '/Ancestor.php'; + + require_once __DIR__ . '/Child.php'; + + new Child6382; + } +} diff --git a/tests/end-to-end/regression/6391.phpt b/tests/end-to-end/regression/6391.phpt new file mode 100644 index 00000000000..4fd143adb31 --- /dev/null +++ b/tests/end-to-end/regression/6391.phpt @@ -0,0 +1,34 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6391 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Event Facade Sealed +Test Suite Loaded (1 test) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (1 test) +Test Suite Started (TestFixture\Issue6391\Issue6391Test, 1 test) +Before First Test Method Called (TestFixture\Issue6391\Issue6391Test::setUpBeforeClass) +Before First Test Method Finished: +- TestFixture\Issue6391\Issue6391Test::setUpBeforeClass +Test Preparation Started (TestFixture\Issue6391\Issue6391Test::testOne) +Test Preparation Failed (TestFixture\Issue6391\Issue6391Test::testOne) +Object of class TestFixture\Issue6391\Issue6391 could not be converted to string +Test Errored (TestFixture\Issue6391\Issue6391Test::testOne) +Object of class TestFixture\Issue6391\Issue6391 could not be converted to string +Test Suite Finished (TestFixture\Issue6391\Issue6391Test, 1 test) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 2) diff --git a/tests/end-to-end/regression/6391/src/Issue6391.php b/tests/end-to-end/regression/6391/src/Issue6391.php new file mode 100644 index 00000000000..2b7741f8e84 --- /dev/null +++ b/tests/end-to-end/regression/6391/src/Issue6391.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\Issue6391; + +use Error; + +class Issue6391 +{ + public static $instance; + + public function __unserialize(array $data): void + { + throw new Error("Cannot unserialize '{$this}'"); + } +} diff --git a/tests/end-to-end/regression/6391/tests/Issue6391Test.php b/tests/end-to-end/regression/6391/tests/Issue6391Test.php new file mode 100644 index 00000000000..e496413dcf2 --- /dev/null +++ b/tests/end-to-end/regression/6391/tests/Issue6391Test.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace TestFixture\Issue6391; + +use PHPUnit\Framework\TestCase; + +require __DIR__ . '/../src/Issue6391.php'; + +final class Issue6391Test extends TestCase +{ + public static function setUpBeforeClass(): void + { + Issue6391::$instance = new Issue6391; + } + + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6406.phpt b/tests/end-to-end/regression/6406.phpt new file mode 100644 index 00000000000..e265d5c1de1 --- /dev/null +++ b/tests/end-to-end/regression/6406.phpt @@ -0,0 +1,21 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6406 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +.. 2 / 2 (100%) + +Time: %s, Memory: %s + +OK (2 tests, 2 assertions) diff --git a/tests/end-to-end/regression/6406/Issue6406Test.php b/tests/end-to-end/regression/6406/Issue6406Test.php new file mode 100644 index 00000000000..a3de5a9b79a --- /dev/null +++ b/tests/end-to-end/regression/6406/Issue6406Test.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6406; + +use const INF; +use const NAN; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class Issue6406Test extends TestCase +{ + public static function provider(): array + { + return [ + 'inf' => [INF], + 'nan' => [NAN], + ]; + } + + #[DataProvider('provider')] + public function testOne($value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/6408.phpt b/tests/end-to-end/regression/6408.phpt new file mode 100644 index 00000000000..de8d5ed2ceb --- /dev/null +++ b/tests/end-to-end/regression/6408.phpt @@ -0,0 +1,31 @@ +--TEST-- +https://github.com/sebastianbergmann/phpunit/issues/6408 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\Issue6408\Issue6408Test::testFoo +The data provider specified for PHPUnit\TestFixture\Issue6408\Issue6408Test::testFoo is invalid +a users exception from data-provider context + +%sIssue6408Test.php:%d + +-- + +There was 1 PHPUnit test runner warning: + +1) No tests found in class "PHPUnit\TestFixture\Issue6408\Issue6408Test". + +No tests executed! diff --git a/tests/end-to-end/regression/6408/Issue6408Test.php b/tests/end-to-end/regression/6408/Issue6408Test.php new file mode 100644 index 00000000000..2f3ceed75dc --- /dev/null +++ b/tests/end-to-end/regression/6408/Issue6408Test.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\Issue6408; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +final class Issue6408Test extends TestCase +{ + public static function provideData(): iterable + { + yield from self::gatherAssertTypes(); + } + + public static function gatherAssertTypes(): array + { + throw new RuntimeException('a users exception from data-provider context'); + } + + #[DataProvider('provideData')] + public function testFoo(): void + { + } +} diff --git a/tests/end-to-end/regression/74.phpt b/tests/end-to-end/regression/74.phpt new file mode 100644 index 00000000000..5d7050a9fd7 --- /dev/null +++ b/tests/end-to-end/regression/74.phpt @@ -0,0 +1,30 @@ +--TEST-- +GH-74: catchable fatal error in 3.5 +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +E 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 error: + +1) PHPUnit\TestFixture\Issue74Test::testCreateAndThrowNewExceptionInProcessIsolation +PHPUnit\TestFixture\NewException: Testing GH-74 + +%sIssue74Test.php:%d + +ERRORS! +Tests: 1, Assertions: 0, Errors: 1. diff --git a/tests/end-to-end/regression/74/Issue74Test.php b/tests/end-to-end/regression/74/Issue74Test.php new file mode 100644 index 00000000000..ea1b16e9ca3 --- /dev/null +++ b/tests/end-to-end/regression/74/Issue74Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\TestCase; + +class Issue74Test extends TestCase +{ + public function testCreateAndThrowNewExceptionInProcessIsolation(): void + { + require_once __DIR__ . '/NewException.php'; + + throw new NewException('Testing GH-74'); + } +} diff --git a/tests/end-to-end/regression/74/NewException.php b/tests/end-to-end/regression/74/NewException.php new file mode 100644 index 00000000000..7b1526250f3 --- /dev/null +++ b/tests/end-to-end/regression/74/NewException.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; + +class NewException extends Exception +{ +} diff --git a/tests/end-to-end/regression/765.phpt b/tests/end-to-end/regression/765.phpt new file mode 100644 index 00000000000..062b85ce739 --- /dev/null +++ b/tests/end-to-end/regression/765.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-765: Fatal error triggered in PHPUnit when exception is thrown in data provider of a test with a dependency +--SKIPIF-- +run($_SERVER['argv'])); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\Issue765Test::testDependent +The data provider PHPUnit\TestFixture\Issue765Test::dependentProvider specified for PHPUnit\TestFixture\Issue765Test::testDependent is invalid + + +%s:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. +int(2) diff --git a/tests/end-to-end/regression/765/Issue765Test.php b/tests/end-to-end/regression/765/Issue765Test.php new file mode 100644 index 00000000000..5dfd61bcd1a --- /dev/null +++ b/tests/end-to-end/regression/765/Issue765Test.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\TestCase; + +class Issue765Test extends TestCase +{ + public static function dependentProvider(): void + { + throw new Exception; + } + + public function testDependee(): void + { + $this->assertTrue(true); + } + + #[Depends('testDependee')] + #[DataProvider('dependentProvider')] + public function testDependent($a): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/regression/797.phpt b/tests/end-to-end/regression/797.phpt new file mode 100644 index 00000000000..ee556987d7b --- /dev/null +++ b/tests/end-to-end/regression/797.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-797: Disabled $preserveGlobalState does not load bootstrap.php. +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/regression/797/Issue797Test.php b/tests/end-to-end/regression/797/Issue797Test.php new file mode 100644 index 00000000000..07ed61ac5b7 --- /dev/null +++ b/tests/end-to-end/regression/797/Issue797Test.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture; + +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\TestCase; + +#[PreserveGlobalState(true)] +class Issue797Test extends TestCase +{ + public function testBootstrapPhpIsExecutedInIsolation(): void + { + $this->assertEquals(GITHUB_ISSUE, 797); + } +} diff --git a/tests/end-to-end/regression/797/bootstrap797.php b/tests/end-to-end/regression/797/bootstrap797.php new file mode 100644 index 00000000000..68b036c2c2e --- /dev/null +++ b/tests/end-to-end/regression/797/bootstrap797.php @@ -0,0 +1,14 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +// PHPUnit_Framework_TestCase itself does not exist. :-) +require_once __DIR__ . '/../../../bootstrap.php'; + +const GITHUB_ISSUE = 797; diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/phpunit.xml b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/phpunit.xml new file mode 100644 index 00000000000..20c26dddd85 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/src/.gitkeep b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/src/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/tests/DeprecationInTestCodeTest.php b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/tests/DeprecationInTestCodeTest.php new file mode 100644 index 00000000000..1213b7f2d2e --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code-ignored/tests/DeprecationInTestCodeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class DeprecationInTestCodeTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/phpunit.xml b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/phpunit.xml new file mode 100644 index 00000000000..a501786e420 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/phpunit.xml @@ -0,0 +1,16 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/src/.gitkeep b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/src/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/tests/DeprecationInTestCodeTest.php b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/tests/DeprecationInTestCodeTest.php new file mode 100644 index 00000000000..1213b7f2d2e --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/deprecation-in-test-code/tests/DeprecationInTestCodeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class DeprecationInTestCodeTest extends TestCase +{ + public function testOne(): void + { + trigger_error('message', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/phpunit.xml b/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/phpunit.xml new file mode 100644 index 00000000000..f2237a09c1d --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/phpunit.xml @@ -0,0 +1,18 @@ + + + + + tests + + + + + + does_not_exist + invalid-string + DoesNotExist::doesNotExist + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/tests/ExampleTest.php b/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/tests/ExampleTest.php new file mode 100644 index 00000000000..e99f90f5b79 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/invalid-deprecation-trigger/tests/ExampleTest.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class ExampleTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/phpunit.xml b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/phpunit.xml new file mode 100644 index 00000000000..5c0fcac4da1 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/phpunit.xml @@ -0,0 +1,17 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/src/FirstPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/tests/FirstPartyClassTest.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/ThirdPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..b373e4addad --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/ThirdPartyClass.php @@ -0,0 +1,15 @@ +method(); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/autoload.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/autoload.php new file mode 100644 index 00000000000..95f0626f283 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct-indirect/vendor/autoload.php @@ -0,0 +1,3 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/src/FirstPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/tests/FirstPartyClassTest.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/ThirdPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..b373e4addad --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/ThirdPartyClass.php @@ -0,0 +1,15 @@ +method(); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/autoload.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/autoload.php new file mode 100644 index 00000000000..95f0626f283 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self-direct/vendor/autoload.php @@ -0,0 +1,3 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/src/FirstPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/tests/FirstPartyClassTest.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/ThirdPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..b373e4addad --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/ThirdPartyClass.php @@ -0,0 +1,15 @@ +method(); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/autoload.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/autoload.php new file mode 100644 index 00000000000..95f0626f283 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation-report-self/vendor/autoload.php @@ -0,0 +1,3 @@ + + + + + tests + + + + + + src + + + diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation/src/FirstPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/src/FirstPartyClass.php new file mode 100644 index 00000000000..aca0b8b8d05 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/src/FirstPartyClass.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use const E_USER_DEPRECATED; +use function trigger_error; + +final class FirstPartyClass +{ + public function method(): true + { + (new ThirdPartyClass)->method(); + + @trigger_error('deprecation in first-party code', E_USER_DEPRECATED); + + return true; + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation/tests/FirstPartyClassTest.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/tests/FirstPartyClassTest.php new file mode 100644 index 00000000000..1abafab73ab --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/tests/FirstPartyClassTest.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\SelfDirectIndirect; + +use PHPUnit\Framework\TestCase; + +final class FirstPartyClassTest extends TestCase +{ + public function testOne(): void + { + $this->assertTrue((new FirstPartyClass)->method()); + } + + public function testTwo(): void + { + $this->assertTrue((new ThirdPartyClass)->anotherMethod()); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/ThirdPartyClass.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/ThirdPartyClass.php new file mode 100644 index 00000000000..b373e4addad --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/ThirdPartyClass.php @@ -0,0 +1,15 @@ +method(); + } +} diff --git a/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/autoload.php b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/autoload.php new file mode 100644 index 00000000000..95f0626f283 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/_files/user-deprecation/vendor/autoload.php @@ -0,0 +1,3 @@ +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %sphpunit.xml + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/self-direct-indirect/deprecation-in-test-code.phpt b/tests/end-to-end/self-direct-indirect/deprecation-in-test-code.phpt new file mode 100644 index 00000000000..e9d2738339e --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/deprecation-in-test-code.phpt @@ -0,0 +1,29 @@ +--TEST-- +Deprecation in test code is reported when it is configured to be reported +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %sphpunit.xml + +D 1 / 1 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 deprecation: + +1) %sDeprecationInTestCodeTest.php:20 +message + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/end-to-end/self-direct-indirect/invalid-deprecation-trigger.phpt b/tests/end-to-end/self-direct-indirect/invalid-deprecation-trigger.phpt new file mode 100644 index 00000000000..9819d857571 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/invalid-deprecation-trigger.phpt @@ -0,0 +1,32 @@ +--TEST-- +Test Runner warnings are displayed correctly when invalid deprecation triggers are configured in the XML configuration file +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +. 1 / 1 (100%) + +Time: %s, Memory: %s + +There were 3 PHPUnit test runner warnings: + +1) Function does_not_exist cannot be configured as a deprecation trigger because it is not declared + +2) invalid-string cannot be configured as a deprecation trigger because it is not in ClassName::methodName format + +3) Method DoesNotExist::doesNotExist cannot be configured as a deprecation trigger because it is not declared + +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 3. diff --git a/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct-indirect.phpt b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct-indirect.phpt new file mode 100644 index 00000000000..d0bd429c5e1 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct-indirect.phpt @@ -0,0 +1,48 @@ +--TEST-- +All deprecations are reported when deprecations triggered from first-party code and deprecations triggered from third-party code should be reported +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DD 2 / 2 (100%) + +Time: %s, Memory: %s + +2 tests triggered 2 deprecations: + +1) %sThirdPartyClass.php:8 +deprecation in third-party code + +Triggered by: + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne + %s:16 + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo + %s:21 + +2) %sFirstPartyClass.php:21 +deprecation in first-party code + +Triggered by: + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne + %sFirstPartyClassTest.php:16 + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo + %sFirstPartyClassTest.php:21 + +OK, but there were issues! +Tests: 2, Assertions: 2, Deprecations: 2. diff --git a/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct.phpt b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct.phpt new file mode 100644 index 00000000000..cc3f8a3e302 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self-direct.phpt @@ -0,0 +1,45 @@ +--TEST-- +The correct deprecations are reported when deprecations triggered from third-party code should be ignored +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +DD 2 / 2 (100%) + +Time: %s, Memory: %s + +2 tests triggered 2 deprecations: + +1) %sThirdPartyClass.php:8 +deprecation in third-party code + +Triggered by: + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne + %s:16 + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo + %s:21 + +2) %sFirstPartyClass.php:21 +deprecation in first-party code + +Triggered by: + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne + %sFirstPartyClassTest.php:16 + +OK, but there were issues! +Tests: 2, Assertions: 2, Deprecations: 2. diff --git a/tests/end-to-end/self-direct-indirect/user-deprecation-report-self.phpt b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self.phpt new file mode 100644 index 00000000000..52362fca891 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/user-deprecation-report-self.phpt @@ -0,0 +1,34 @@ +--TEST-- +The correct deprecations are reported when only deprecations in first-party code triggered from first-party code should be reported +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s +Configuration: %s + +D. 2 / 2 (100%) + +Time: %s, Memory: %s + +1 test triggered 1 deprecation: + +1) %sFirstPartyClass.php:21 +deprecation in first-party code + +Triggered by: + +* PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne + %sFirstPartyClassTest.php:16 + +OK, but there were issues! +Tests: 2, Assertions: 2, Deprecations: 1. diff --git a/tests/end-to-end/self-direct-indirect/user-deprecation.phpt b/tests/end-to-end/self-direct-indirect/user-deprecation.phpt new file mode 100644 index 00000000000..0d9bb5cf2a3 --- /dev/null +++ b/tests/end-to-end/self-direct-indirect/user-deprecation.phpt @@ -0,0 +1,46 @@ +--TEST-- +The right events are emitted in the right order for a test that runs code which triggers E_USER_DEPRECATED +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit Started (PHPUnit %s using %s) +Test Runner Configured +Bootstrap Finished (%sautoload.php) +Event Facade Sealed +Test Suite Loaded (2 tests) +Test Runner Started +Test Suite Sorted +Test Runner Execution Started (2 tests) +Test Suite Started (%sphpunit.xml, 2 tests) +Test Suite Started (default, 2 tests) +Test Suite Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne, issue triggered by first-party code calling into first-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testOne) +Test Preparation Started (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Prepared (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by first-party code calling into third-party code, suppressed using operator) in %s:%d +deprecation in third-party code +Test Triggered Deprecation (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo, issue triggered by third-party code, suppressed using operator) in %s:%d +deprecation in first-party code +Test Passed (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest::testTwo) +Test Suite Finished (PHPUnit\TestFixture\SelfDirectIndirect\FirstPartyClassTest, 2 tests) +Test Suite Finished (default, 2 tests) +Test Suite Finished (%sphpunit.xml, 2 tests) +Test Runner Execution Finished +Test Runner Finished +PHPUnit Finished (Shell Exit Code: 0) diff --git a/tests/end-to-end/testdox/_files/Bar.php b/tests/end-to-end/testdox/_files/Bar.php new file mode 100644 index 00000000000..08d71b13f74 --- /dev/null +++ b/tests/end-to-end/testdox/_files/Bar.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +enum Bar +{ + case FOO; +} diff --git a/tests/end-to-end/testdox/_files/CamelCaseTest.php b/tests/end-to-end/testdox/_files/CamelCaseTest.php new file mode 100644 index 00000000000..74c6c708177 --- /dev/null +++ b/tests/end-to-end/testdox/_files/CamelCaseTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\TestCase; + +final class CamelCaseTest extends TestCase +{ + public function testSomethingThatWorks(): void + { + $this->assertTrue(true); + } + + public function testSomethingThatDoesNotWork(): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataTest.php b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataTest.php new file mode 100644 index 00000000000..16fd815c295 --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Text from class-level TestDox metadata')] +final class DataProviderWithNumericDataSetNameAndMetadataTest extends TestCase +{ + public static function provider(): array + { + return [ + 0 => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + ], + ]; + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for successful test')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for failing test')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataWithPlaceholdersTest.php b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataWithPlaceholdersTest.php new file mode 100644 index 00000000000..74d626baa3d --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameAndMetadataWithPlaceholdersTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Text from class-level TestDox metadata')] +final class DataProviderWithNumericDataSetNameAndMetadataWithPlaceholdersTest extends TestCase +{ + public static function provider(): array + { + return [ + 0 => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + Foo::BAR, + Bar::FOO, + ], + ]; + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for successful test with placeholders ($a, $b, $c, $d, $e, $f, $g)')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e, Foo $f, Bar $g): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for failing test with placeholders ($a, $b, $c, $d, $e, $f, $g)')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e, Foo $f, Bar $g): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameTest.php b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameTest.php new file mode 100644 index 00000000000..3fd259c9a0d --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithNumericDataSetNameTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderWithNumericDataSetNameTest extends TestCase +{ + public static function provider(): array + { + return [ + 0 => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + ], + ]; + } + + #[DataProvider('provider')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataTest.php b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataTest.php new file mode 100644 index 00000000000..eaae55d805e --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Text from class-level TestDox metadata')] +final class DataProviderWithStringDataSetNameAndMetadataTest extends TestCase +{ + public static function provider(): array + { + return [ + 'data set name' => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + ], + ]; + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for successful test')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for failing test')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataWithPlaceholdersTest.php b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataWithPlaceholdersTest.php new file mode 100644 index 00000000000..ac4b397d4f9 --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameAndMetadataWithPlaceholdersTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Text from class-level TestDox metadata')] +final class DataProviderWithStringDataSetNameAndMetadataWithPlaceholdersTest extends TestCase +{ + public static function provider(): array + { + return [ + 'data set name' => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + Foo::BAR, + Bar::FOO, + ], + ]; + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for successful test with placeholders ($a, $b, $c, $d, $e, $f, $g)')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e, Foo $f, Bar $g): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + #[TestDox('Text from method-level TestDox metadata for failing test with placeholders ($a, $b, $c, $d, $e, $f, $g)')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e, Foo $f, Bar $g): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameTest.php b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameTest.php new file mode 100644 index 00000000000..556bb1c9998 --- /dev/null +++ b/tests/end-to-end/testdox/_files/DataProviderWithStringDataSetNameTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; + +final class DataProviderWithStringDataSetNameTest extends TestCase +{ + public static function provider(): array + { + return [ + 'data set name' => [ + 'string', + 0, + 0.0, + ['key' => 'value'], + true, + ], + ]; + } + + #[DataProvider('provider')] + public function testSomethingThatWorks(string $a, int $b, float $c, array $d, bool $e): void + { + $this->assertTrue(true); + } + + #[DataProvider('provider')] + public function testSomethingThatDoesNotWork(string $a, int $b, float $c, array $d, bool $e): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/DeprecationTest.php b/tests/end-to-end/testdox/_files/DeprecationTest.php new file mode 100644 index 00000000000..14377d714c6 --- /dev/null +++ b/tests/end-to-end/testdox/_files/DeprecationTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class DeprecationTest extends TestCase +{ + public function testDeprecation(): void + { + trigger_error('deprecation', E_USER_DEPRECATED); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/DiffTest.php b/tests/end-to-end/testdox/_files/DiffTest.php new file mode 100644 index 00000000000..58b54d8ddd6 --- /dev/null +++ b/tests/end-to-end/testdox/_files/DiffTest.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\TestCase; + +final class DiffTest extends TestCase +{ + public function testSomethingThatDoesNotWork(): void + { + $this->assertEquals( + "foo\nbar\nbaz\n", + "foo\nbaz\nbar\n", + ); + } +} diff --git a/tests/end-to-end/testdox/_files/Foo.php b/tests/end-to-end/testdox/_files/Foo.php new file mode 100644 index 00000000000..9f4cc089428 --- /dev/null +++ b/tests/end-to-end/testdox/_files/Foo.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +enum Foo: string +{ + case BAR = 'bar'; +} diff --git a/tests/end-to-end/testdox/_files/FormatterMethodDoesNotExistTest.php b/tests/end-to-end/testdox/_files/FormatterMethodDoesNotExistTest.php new file mode 100644 index 00000000000..97a7cb5ce71 --- /dev/null +++ b/tests/end-to-end/testdox/_files/FormatterMethodDoesNotExistTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class FormatterMethodDoesNotExistTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + ['string'], + ]; + } + + #[DataProvider('provider')] + #[TestDoxFormatter('formatter')] + public function testOne(string $value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/FormatterMethodIsNotPublicTest.php b/tests/end-to-end/testdox/_files/FormatterMethodIsNotPublicTest.php new file mode 100644 index 00000000000..df773a153d6 --- /dev/null +++ b/tests/end-to-end/testdox/_files/FormatterMethodIsNotPublicTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class FormatterMethodIsNotPublicTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + ['string'], + ]; + } + + #[DataProvider('provider')] + #[TestDoxFormatter('formatter')] + public function testOne(string $value): void + { + $this->assertTrue(true); + } + + private static function formatter(string $value): string + { + return 'formatted ' . $value; + } +} diff --git a/tests/end-to-end/testdox/_files/FormatterMethodIsNotStaticTest.php b/tests/end-to-end/testdox/_files/FormatterMethodIsNotStaticTest.php new file mode 100644 index 00000000000..1fe952d51d4 --- /dev/null +++ b/tests/end-to-end/testdox/_files/FormatterMethodIsNotStaticTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class FormatterMethodIsNotStaticTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + ['string'], + ]; + } + + public function formatter(string $value): string + { + return 'formatted ' . $value; + } + + #[DataProvider('provider')] + #[TestDoxFormatter('formatter')] + public function testOne(string $value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/FormatterMethodThrowsExceptionTest.php b/tests/end-to-end/testdox/_files/FormatterMethodThrowsExceptionTest.php new file mode 100644 index 00000000000..e5848875565 --- /dev/null +++ b/tests/end-to-end/testdox/_files/FormatterMethodThrowsExceptionTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use Exception; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class FormatterMethodThrowsExceptionTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + ['string'], + ]; + } + + public static function formatter(string $value): string + { + throw new Exception('message'); + } + + #[DataProvider('provider')] + #[TestDoxFormatter('formatter')] + public function testOne(string $value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/FormatterTest.php b/tests/end-to-end/testdox/_files/FormatterTest.php new file mode 100644 index 00000000000..ef1a905d4a5 --- /dev/null +++ b/tests/end-to-end/testdox/_files/FormatterTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\TestCase; + +final class FormatterTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + ['string'], + ]; + } + + public static function formatter(string $value): string + { + return 'formatted ' . $value; + } + + #[DataProvider('provider')] + #[TestDoxFormatter('formatter')] + public function testOne(string $value): void + { + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/MetadataTest.php b/tests/end-to-end/testdox/_files/MetadataTest.php new file mode 100644 index 00000000000..471dc344742 --- /dev/null +++ b/tests/end-to-end/testdox/_files/MetadataTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[TestDox('Text from class-level TestDox metadata')] +final class MetadataTest extends TestCase +{ + #[TestDox('Text from method-level TestDox metadata for successful test')] + public function testSomethingThatWorks(): void + { + $this->assertTrue(true); + } + + #[TestDox('Text from method-level TestDox metadata for failing test')] + public function testSomethingThatDoesNotWork(): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/NoticeTest.php b/tests/end-to-end/testdox/_files/NoticeTest.php new file mode 100644 index 00000000000..94f71d4d02e --- /dev/null +++ b/tests/end-to-end/testdox/_files/NoticeTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use const E_USER_NOTICE; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class NoticeTest extends TestCase +{ + public function testNotice(): void + { + trigger_error('notice', E_USER_NOTICE); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/OutcomeAndIssuesTest.php b/tests/end-to-end/testdox/_files/OutcomeAndIssuesTest.php new file mode 100644 index 00000000000..225df8c2594 --- /dev/null +++ b/tests/end-to-end/testdox/_files/OutcomeAndIssuesTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use const E_USER_DEPRECATED; +use const E_USER_NOTICE; +use const E_USER_WARNING; +use function trigger_error; +use Exception; +use PHPUnit\Framework\TestCase; + +final class OutcomeAndIssuesTest extends TestCase +{ + public function testSuccess(): void + { + $this->assertTrue(true); + } + + public function testSuccessButRisky(): void + { + } + + public function testSuccessButDeprecation(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_DEPRECATED); + } + + public function testSuccessButNotice(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_NOTICE); + } + + public function testSuccessButWarning(): void + { + $this->assertTrue(true); + + trigger_error('message', E_USER_WARNING); + } + + public function testFailure(): void + { + $this->assertTrue(false); + } + + public function testError(): void + { + throw new Exception('message'); + } + + public function testIncomplete(): void + { + $this->markTestIncomplete('message'); + } + + public function testSkipped(): void + { + $this->markTestSkipped('message'); + } +} diff --git a/tests/end-to-end/testdox/_files/RiskyTest.php b/tests/end-to-end/testdox/_files/RiskyTest.php new file mode 100644 index 00000000000..c09f7074646 --- /dev/null +++ b/tests/end-to-end/testdox/_files/RiskyTest.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\TestCase; + +final class RiskyTest extends TestCase +{ + public function test_this_is_a_useless_test_that_does_not_test_anything(): void + { + } +} diff --git a/tests/end-to-end/testdox/_files/SnakeCaseTest.php b/tests/end-to-end/testdox/_files/SnakeCaseTest.php new file mode 100644 index 00000000000..3bbe34500d2 --- /dev/null +++ b/tests/end-to-end/testdox/_files/SnakeCaseTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use PHPUnit\Framework\TestCase; + +final class SnakeCaseTest extends TestCase +{ + public function test_something_that_works(): void + { + $this->assertTrue(true); + } + + public function test_something_that_does_not_work(): void + { + /* @noinspection PhpUnitAssertTrueWithIncompatibleTypeArgumentInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/end-to-end/testdox/_files/WarningTest.php b/tests/end-to-end/testdox/_files/WarningTest.php new file mode 100644 index 00000000000..c92c5c4a61f --- /dev/null +++ b/tests/end-to-end/testdox/_files/WarningTest.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TestFixture\TestDox; + +use const E_USER_WARNING; +use function trigger_error; +use PHPUnit\Framework\TestCase; + +final class WarningTest extends TestCase +{ + public function testWarning(): void + { + trigger_error('warning', E_USER_WARNING); + + $this->assertTrue(true); + } +} diff --git a/tests/end-to-end/testdox/_files/bootstrap.php b/tests/end-to-end/testdox/_files/bootstrap.php new file mode 100644 index 00000000000..cea41cada23 --- /dev/null +++ b/tests/end-to-end/testdox/_files/bootstrap.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +require __DIR__ . '/Foo.php'; + +require __DIR__ . '/Bar.php'; diff --git a/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name-colorized.phpt b/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name-colorized.phpt new file mode 100644 index 00000000000..7328bdd78e6 --- /dev/null +++ b/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; No TestDox metadata; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Data Provider With Numeric Data Set Name (PHPUnit\TestFixture\TestDox\DataProviderWithNumericDataSetName) + ✔ Something that works with data set 0 + ✘ Something that does not work with data set 0 + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithNumericDataSetNameTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name.phpt b/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name.phpt new file mode 100644 index 00000000000..5fa8c3fba19 --- /dev/null +++ b/tests/end-to-end/testdox/data-provider-with-numeric-data-set-name.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; No TestDox metadata +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Data Provider With Numeric Data Set Name (PHPUnit\TestFixture\TestDox\DataProviderWithNumericDataSetName) + ✔ Something that works with data set #0 + ✘ Something that does not work with data set #0 + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/data-provider-with-string-data-set-name-colorized.phpt b/tests/end-to-end/testdox/data-provider-with-string-data-set-name-colorized.phpt new file mode 100644 index 00000000000..2cf11575f92 --- /dev/null +++ b/tests/end-to-end/testdox/data-provider-with-string-data-set-name-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; No TestDox metadata; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Data Provider With String Data Set Name (PHPUnit\TestFixture\TestDox\DataProviderWithStringDataSetName) + ✔ Something that works with data·set·name + ✘ Something that does not work with data·set·name + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithStringDataSetNameTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/data-provider-with-string-data-set-name.phpt b/tests/end-to-end/testdox/data-provider-with-string-data-set-name.phpt new file mode 100644 index 00000000000..111e0b8f8ed --- /dev/null +++ b/tests/end-to-end/testdox/data-provider-with-string-data-set-name.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; No TestDox metadata +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Data Provider With String Data Set Name (PHPUnit\TestFixture\TestDox\DataProviderWithStringDataSetName) + ✔ Something that works with data set "data set name" + ✘ Something that does not work with data set "data set name" + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/diff-colorized-windows.phpt b/tests/end-to-end/testdox/diff-colorized-windows.phpt new file mode 100644 index 00000000000..33afae323f9 --- /dev/null +++ b/tests/end-to-end/testdox/diff-colorized-windows.phpt @@ -0,0 +1,44 @@ +--TEST-- +TestDox: Diff; Colorized; Windows +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Diff (PHPUnit\TestFixture\TestDox\Diff) + ✘ Something that does not work + ┐ + ├ Failed asserting that two strings are equal. + ├ --- Expected  + ├ +++ Actual  + ├ @@ @@  + ├  'foo\n  + ├ +baz\n  + ├  bar\n  + ├ -baz\n  + ├  '  + │ + │ %s_files%eDiffTest.php:%d + ┴ + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/testdox/diff-colorized.phpt b/tests/end-to-end/testdox/diff-colorized.phpt new file mode 100644 index 00000000000..16635fff496 --- /dev/null +++ b/tests/end-to-end/testdox/diff-colorized.phpt @@ -0,0 +1,44 @@ +--TEST-- +TestDox: Diff; Colorized; *nix +--SKIPIF-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Diff (PHPUnit\TestFixture\TestDox\Diff) + ✘ Something that does not work + ┐ + ├ Failed asserting that two strings are equal. + ┊ ---·Expected + ┊ +++·Actual + ┊ @@ @@ + ┊ 'foo\n + ┊ +baz\n + ┊ bar\n + ┊ -baz\n + ┊ ' + │ + │ %s_files%eDiffTest.php:%d + ┴ + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/testdox/diff.phpt b/tests/end-to-end/testdox/diff.phpt new file mode 100644 index 00000000000..b30e825b263 --- /dev/null +++ b/tests/end-to-end/testdox/diff.phpt @@ -0,0 +1,39 @@ +--TEST-- +TestDox: Diff +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Diff (PHPUnit\TestFixture\TestDox\Diff) + ✘ Something that does not work + │ + │ Failed asserting that two strings are equal. + │ --- Expected + │ +++ Actual + │ @@ @@ + │ 'foo\n + │ +baz\n + │ bar\n + │ -baz\n + │ ' + │ + │ %sDiffTest.php:%d + │ + +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/end-to-end/testdox/formatter-method-does-not-exist.phpt b/tests/end-to-end/testdox/formatter-method-does-not-exist.phpt new file mode 100644 index 00000000000..6b4ebec81aa --- /dev/null +++ b/tests/end-to-end/testdox/formatter-method-does-not-exist.phpt @@ -0,0 +1,33 @@ +--TEST-- +#[TestDoxFormatter]: Formatter method does not exist +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Formatter Method Does Not Exist (PHPUnit\TestFixture\TestDox\FormatterMethodDoesNotExist) + ✔ One with data set #0 + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\TestDox\FormatterMethodDoesNotExistTest::testOne#0 with data ('string') +Method PHPUnit\TestFixture\TestDox\FormatterMethodDoesNotExistTest::formatter() cannot be used as a TestDox formatter because it does not exist + +%sFormatterMethodDoesNotExistTest.php:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/testdox/formatter-method-is-not-public.phpt b/tests/end-to-end/testdox/formatter-method-is-not-public.phpt new file mode 100644 index 00000000000..1f62c536847 --- /dev/null +++ b/tests/end-to-end/testdox/formatter-method-is-not-public.phpt @@ -0,0 +1,33 @@ +--TEST-- +#[TestDoxFormatter]: Formatter method is not public +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Formatter Method Is Not Public (PHPUnit\TestFixture\TestDox\FormatterMethodIsNotPublic) + ✔ One with data set #0 + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\TestDox\FormatterMethodIsNotPublicTest::testOne#0 with data ('string') +Method PHPUnit\TestFixture\TestDox\FormatterMethodIsNotPublicTest::formatter() cannot be used as a TestDox formatter because it is not public + +%sFormatterMethodIsNotPublicTest.php:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/testdox/formatter-method-is-not-static.phpt b/tests/end-to-end/testdox/formatter-method-is-not-static.phpt new file mode 100644 index 00000000000..6e78da51bce --- /dev/null +++ b/tests/end-to-end/testdox/formatter-method-is-not-static.phpt @@ -0,0 +1,33 @@ +--TEST-- +#[TestDoxFormatter]: Formatter method is not static +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Formatter Method Is Not Static (PHPUnit\TestFixture\TestDox\FormatterMethodIsNotStatic) + ✔ One with data set #0 + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\TestDox\FormatterMethodIsNotStaticTest::testOne#0 with data ('string') +Method PHPUnit\TestFixture\TestDox\FormatterMethodIsNotStaticTest::formatter() cannot be used as a TestDox formatter because it is not static + +%sFormatterMethodIsNotStaticTest.php:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/testdox/formatter-method-throws-exception.phpt b/tests/end-to-end/testdox/formatter-method-throws-exception.phpt new file mode 100644 index 00000000000..7f884c1d1b1 --- /dev/null +++ b/tests/end-to-end/testdox/formatter-method-throws-exception.phpt @@ -0,0 +1,34 @@ +--TEST-- +#[TestDoxFormatter]: Formatter method throws exception +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Formatter Method Throws Exception (PHPUnit\TestFixture\TestDox\FormatterMethodThrowsException) + ✔ One with data set #0 + +There was 1 PHPUnit error: + +1) PHPUnit\TestFixture\TestDox\FormatterMethodThrowsExceptionTest::testOne#0 with data ('string') +TestDox formatter PHPUnit\TestFixture\TestDox\FormatterMethodThrowsExceptionTest::formatter() triggered an error: message +%sFormatterMethodThrowsExceptionTest.php:%d + +%sFormatterMethodThrowsExceptionTest.php:%d + +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/end-to-end/testdox/formatter.phpt b/tests/end-to-end/testdox/formatter.phpt new file mode 100644 index 00000000000..852138db2db --- /dev/null +++ b/tests/end-to-end/testdox/formatter.phpt @@ -0,0 +1,25 @@ +--TEST-- +#[TestDoxFormatter]: Correct use +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Formatter (PHPUnit\TestFixture\TestDox\Formatter) + ✔ formatted string + +OK (1 test, 1 assertion) diff --git a/tests/end-to-end/testdox/metadata-colorized.phpt b/tests/end-to-end/testdox/metadata-colorized.phpt new file mode 100644 index 00000000000..a40b00b915a --- /dev/null +++ b/tests/end-to-end/testdox/metadata-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; TestDox metadata; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test + ✘ Text from method-level TestDox metadata for failing test + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eMetadataTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name-colorized.phpt b/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name-colorized.phpt new file mode 100644 index 00000000000..40195ecd6ce --- /dev/null +++ b/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; TestDox metadata without placeholders; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with data set 0 + ✘ Text from method-level TestDox metadata for failing test with data set 0 + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithNumericDataSetNameAndMetadataTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name.phpt b/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name.phpt new file mode 100644 index 00000000000..66a02221372 --- /dev/null +++ b/tests/end-to-end/testdox/metadata-data-provider-with-numeric-data-set-name.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; TestDox metadata without placeholders +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with data set #0 + ✘ Text from method-level TestDox metadata for failing test with data set #0 + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name-colorized.phpt b/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name-colorized.phpt new file mode 100644 index 00000000000..0f8554b8404 --- /dev/null +++ b/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with string data set name; TestDox metadata without placeholders; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with data·set·name + ✘ Text from method-level TestDox metadata for failing test with data·set·name + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithStringDataSetNameAndMetadataTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name.phpt b/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name.phpt new file mode 100644 index 00000000000..1ff84fdf46d --- /dev/null +++ b/tests/end-to-end/testdox/metadata-data-provider-with-string-data-set-name.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Data Provider with string data set name; TestDox metadata without placeholders +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with data set "data set name" + ✘ Text from method-level TestDox metadata for failing test with data set "data set name" + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name-colorized.phpt b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name-colorized.phpt new file mode 100644 index 00000000000..b7fc160f2c7 --- /dev/null +++ b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name-colorized.phpt @@ -0,0 +1,34 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; TestDox metadata with placeholders; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ✘ Text from method-level TestDox metadata for failing test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithNumericDataSetNameAndMetadataWithPlaceholdersTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name.phpt b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name.phpt new file mode 100644 index 00000000000..057df234645 --- /dev/null +++ b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-numeric-data-set-name.phpt @@ -0,0 +1,34 @@ +--TEST-- +TestDox: Default output; Data Provider with numeric data set name; TestDox metadata with placeholders +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ✘ Text from method-level TestDox metadata for failing test with placeholders (string, 0, 0.0, array, true, bar, FOO) + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name-colorized.phpt b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name-colorized.phpt new file mode 100644 index 00000000000..e9d44602b06 --- /dev/null +++ b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name-colorized.phpt @@ -0,0 +1,34 @@ +--TEST-- +TestDox: Default output; Data Provider with string data set name; TestDox metadata with placeholders; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ✘ Text from method-level TestDox metadata for failing test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eDataProviderWithStringDataSetNameAndMetadataWithPlaceholdersTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name.phpt b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name.phpt new file mode 100644 index 00000000000..a4dffe0119c --- /dev/null +++ b/tests/end-to-end/testdox/metadata-with-placeholders-data-provider-with-string-data-set-name.phpt @@ -0,0 +1,34 @@ +--TEST-- +TestDox: Default output; Data Provider with string data set name; TestDox metadata with placeholders +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test with placeholders (string, 0, 0.0, array, true, bar, FOO) + ✘ Text from method-level TestDox metadata for failing test with placeholders (string, 0, 0.0, array, true, bar, FOO) + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/metadata.phpt b/tests/end-to-end/testdox/metadata.phpt new file mode 100644 index 00000000000..a122437474d --- /dev/null +++ b/tests/end-to-end/testdox/metadata.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; TestDox metadata +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Text from class-level TestDox metadata + ✔ Text from method-level TestDox metadata for successful test + ✘ Text from method-level TestDox metadata for failing test + │ + │ Failed asserting that false is true. + │ + │ %s:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/no-metadata-camel-case-colorized.phpt b/tests/end-to-end/testdox/no-metadata-camel-case-colorized.phpt new file mode 100644 index 00000000000..4027d9bcaef --- /dev/null +++ b/tests/end-to-end/testdox/no-metadata-camel-case-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Test name in camel-case notation; No TestDox metadata; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Camel Case (PHPUnit\TestFixture\TestDox\CamelCase) + ✔ Something that works + ✘ Something that does not work + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eCamelCaseTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/no-metadata-camel-case.phpt b/tests/end-to-end/testdox/no-metadata-camel-case.phpt new file mode 100644 index 00000000000..dea35a7ed51 --- /dev/null +++ b/tests/end-to-end/testdox/no-metadata-camel-case.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Test name in camel-case notation; No TestDox metadata +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Camel Case (PHPUnit\TestFixture\TestDox\CamelCase) + ✔ Something that works + ✘ Something that does not work + │ + │ Failed asserting that false is true. + │ + │ %sCamelCaseTest.php:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/no-metadata-snake-case-colorized.phpt b/tests/end-to-end/testdox/no-metadata-snake-case-colorized.phpt new file mode 100644 index 00000000000..8e8c9ada5e0 --- /dev/null +++ b/tests/end-to-end/testdox/no-metadata-snake-case-colorized.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Test name in snake-case notation; No TestDox metadata; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Snake Case (PHPUnit\TestFixture\TestDox\SnakeCase) + ✔ Something that works + ✘ Something that does not work + ┐ + ├ Failed asserting that false is true. + │ + │ %s_files%eSnakeCaseTest.php:%d + ┴ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/no-metadata-snake-case.phpt b/tests/end-to-end/testdox/no-metadata-snake-case.phpt new file mode 100644 index 00000000000..6588faa7ceb --- /dev/null +++ b/tests/end-to-end/testdox/no-metadata-snake-case.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Default output; Test name in snake-case notation; No TestDox metadata +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Snake Case (PHPUnit\TestFixture\TestDox\SnakeCase) + ✔ Something that works + ✘ Something that does not work + │ + │ Failed asserting that false is true. + │ + │ %sSnakeCaseTest.php:%d + │ + +FAILURES! +Tests: 2, Assertions: 2, Failures: 1. diff --git a/tests/end-to-end/testdox/outcome-and-issues-with-summary.phpt b/tests/end-to-end/testdox/outcome-and-issues-with-summary.phpt new file mode 100644 index 00000000000..2aeddcec11d --- /dev/null +++ b/tests/end-to-end/testdox/outcome-and-issues-with-summary.phpt @@ -0,0 +1,110 @@ +--TEST-- +Different outcomes and issues (with TestDox summary) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Outcome And Issues (PHPUnit\TestFixture\TestDox\OutcomeAndIssues) + ✔ Success + ⚠ Success but risky + ⚠ Success but deprecation + ⚠ Success but notice + ⚠ Success but warning + ✘ Failure + │ + │ Failed asserting that false is true. + │ + │ %sOutcomeAndIssuesTest.php:53 + │ + ✘ Error + │ + │ Exception: message + │ + │ %sOutcomeAndIssuesTest.php:58 + │ + ∅ Incomplete + │ + │ message + │ + │ %sOutcomeAndIssuesTest.php:63 + │ + ↩ Skipped + +Summary of tests with errors, failures, or issues: + +Outcome And Issues (PHPUnit\TestFixture\TestDox\OutcomeAndIssues) + ⚠ Success but risky + ⚠ Success but deprecation + ⚠ Success but notice + ⚠ Success but warning + ✘ Failure + │ + │ Failed asserting that false is true. + │ + │ %sOutcomeAndIssuesTest.php:53 + │ + ✘ Error + │ + │ Exception: message + │ + │ %sOutcomeAndIssuesTest.php:58 + │ + ∅ Incomplete + │ + │ message + │ + │ %sOutcomeAndIssuesTest.php:63 + │ + ↩ Skipped + +There was 1 risky test: + +1) PHPUnit\TestFixture\TestDox\OutcomeAndIssuesTest::testSuccessButRisky +This test did not perform any assertions + +%sOutcomeAndIssuesTest.php:26 + +-- + +1 test triggered 1 warning: + +1) %sOutcomeAndIssuesTest.php:48 +message + +-- + +1 test triggered 1 notice: + +1) %sOutcomeAndIssuesTest.php:41 +message + +-- + +1 test triggered 1 deprecation: + +1) %sOutcomeAndIssuesTest.php:34 +message + +ERRORS! +Tests: 9, Assertions: 5, Errors: 1, Failures: 1, Warnings: 1, Deprecations: 1, Notices: 1, Skipped: 1, Incomplete: 1, Risky: 1. diff --git a/tests/end-to-end/testdox/outcome-and-issues-without-summary.phpt b/tests/end-to-end/testdox/outcome-and-issues-without-summary.phpt new file mode 100644 index 00000000000..3a423e8f627 --- /dev/null +++ b/tests/end-to-end/testdox/outcome-and-issues-without-summary.phpt @@ -0,0 +1,82 @@ +--TEST-- +Different outcomes and issues (without TestDox summary) +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Outcome And Issues (PHPUnit\TestFixture\TestDox\OutcomeAndIssues) + ✔ Success + ⚠ Success but risky + ⚠ Success but deprecation + ⚠ Success but notice + ⚠ Success but warning + ✘ Failure + │ + │ Failed asserting that false is true. + │ + │ %sOutcomeAndIssuesTest.php:53 + │ + ✘ Error + │ + │ Exception: message + │ + │ %sOutcomeAndIssuesTest.php:58 + │ + ∅ Incomplete + │ + │ message + │ + │ %sOutcomeAndIssuesTest.php:63 + │ + ↩ Skipped + +There was 1 risky test: + +1) PHPUnit\TestFixture\TestDox\OutcomeAndIssuesTest::testSuccessButRisky +This test did not perform any assertions + +%sOutcomeAndIssuesTest.php:26 + +-- + +1 test triggered 1 warning: + +1) %sOutcomeAndIssuesTest.php:48 +message + +-- + +1 test triggered 1 notice: + +1) %sOutcomeAndIssuesTest.php:41 +message + +-- + +1 test triggered 1 deprecation: + +1) %sOutcomeAndIssuesTest.php:34 +message + +ERRORS! +Tests: 9, Assertions: 5, Errors: 1, Failures: 1, Warnings: 1, Deprecations: 1, Notices: 1, Skipped: 1, Incomplete: 1, Risky: 1. diff --git a/tests/end-to-end/testdox/risky-test-colorized.phpt b/tests/end-to-end/testdox/risky-test-colorized.phpt new file mode 100644 index 00000000000..6b36a558ff2 --- /dev/null +++ b/tests/end-to-end/testdox/risky-test-colorized.phpt @@ -0,0 +1,33 @@ +--TEST-- +TestDox: Risky; Colorized +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Risky (PHPUnit\TestFixture\TestDox\Risky) + ⚠ This is a useless test that does not test anything + +There was 1 risky test: + +1) PHPUnit\TestFixture\TestDox\RiskyTest::test_this_is_a_useless_test_that_does_not_test_anything +This test did not perform any assertions + +%s:16 + +OK, but there were issues! +Tests: 1, Assertions: 0, Risky: 1. diff --git a/tests/end-to-end/testdox/risky-test.phpt b/tests/end-to-end/testdox/risky-test.phpt new file mode 100644 index 00000000000..4cf3ec43df4 --- /dev/null +++ b/tests/end-to-end/testdox/risky-test.phpt @@ -0,0 +1,33 @@ +--TEST-- +TestDox: Risky +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Risky (PHPUnit\TestFixture\TestDox\Risky) + ⚠ This is a useless test that does not test anything + +There was 1 risky test: + +1) PHPUnit\TestFixture\TestDox\RiskyTest::test_this_is_a_useless_test_that_does_not_test_anything +This test did not perform any assertions + +%s:16 + +OK, but there were issues! +Tests: 1, Assertions: 0, Risky: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-deprecation-default.phpt b/tests/end-to-end/testdox/test-that-triggers-deprecation-default.phpt new file mode 100644 index 00000000000..e1a02cdf59e --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-deprecation-default.phpt @@ -0,0 +1,26 @@ +--TEST-- +TestDox: Test triggers deprecation and --display-deprecations is not used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Deprecation (PHPUnit\TestFixture\TestDox\Deprecation) + ⚠ Deprecation + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-deprecation-details.phpt b/tests/end-to-end/testdox/test-that-triggers-deprecation-details.phpt new file mode 100644 index 00000000000..619114598f6 --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-deprecation-details.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Test triggers deprecation and --display-deprecations is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Deprecation (PHPUnit\TestFixture\TestDox\Deprecation) + ⚠ Deprecation + +1 test triggered 1 deprecation: + +1) %sDeprecationTest.php:20 +deprecation + +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-notice-default.phpt b/tests/end-to-end/testdox/test-that-triggers-notice-default.phpt new file mode 100644 index 00000000000..eda8af96993 --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-notice-default.phpt @@ -0,0 +1,26 @@ +--TEST-- +TestDox: Test triggers notice and --display-notices is not used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Notice (PHPUnit\TestFixture\TestDox\Notice) + ⚠ Notice + +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-notice-details.phpt b/tests/end-to-end/testdox/test-that-triggers-notice-details.phpt new file mode 100644 index 00000000000..2c26f02999c --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-notice-details.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Test triggers notice and --display-notices is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Notice (PHPUnit\TestFixture\TestDox\Notice) + ⚠ Notice + +1 test triggered 1 notice: + +1) %sNoticeTest.php:20 +notice + +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-warning-default.phpt b/tests/end-to-end/testdox/test-that-triggers-warning-default.phpt new file mode 100644 index 00000000000..34123752399 --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-warning-default.phpt @@ -0,0 +1,26 @@ +--TEST-- +TestDox: Test triggers warning and --display-warning is not used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Warning (PHPUnit\TestFixture\TestDox\Warning) + ⚠ Warning + +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/end-to-end/testdox/test-that-triggers-warning-details.phpt b/tests/end-to-end/testdox/test-that-triggers-warning-details.phpt new file mode 100644 index 00000000000..1cdc34efb24 --- /dev/null +++ b/tests/end-to-end/testdox/test-that-triggers-warning-details.phpt @@ -0,0 +1,32 @@ +--TEST-- +TestDox: Test triggers warning and --display-warning is used +--FILE-- +run($_SERVER['argv']); +--EXPECTF-- +PHPUnit %s by Sebastian Bergmann and contributors. + +Runtime: %s + +Time: %s, Memory: %s + +Warning (PHPUnit\TestFixture\TestDox\Warning) + ⚠ Warning + +1 test triggered 1 warning: + +1) %sWarningTest.php:20 +warning + +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/unit/Event/AbstractEventTestCase.php b/tests/unit/Event/AbstractEventTestCase.php new file mode 100644 index 00000000000..0dbf1da9876 --- /dev/null +++ b/tests/unit/Event/AbstractEventTestCase.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use function hrtime; +use PHPUnit\Event\Code\TestCollection; +use PHPUnit\Event\Code\TestDoxBuilder; +use PHPUnit\Event\Telemetry\Duration; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Event\TestSuite\TestSuiteWithName; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\MetadataCollection; + +abstract class AbstractEventTestCase extends TestCase +{ + final protected function telemetryInfo(): Telemetry\Info + { + return new Telemetry\Info( + new Telemetry\Snapshot( + HRTime::fromSecondsAndNanoseconds(...hrtime(false)), + Telemetry\MemoryUsage::fromBytes(1000), + Telemetry\MemoryUsage::fromBytes(2000), + new Telemetry\GarbageCollectorStatus(0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, false, false, false, 0), + ), + Duration::fromSecondsAndNanoseconds(123, 456), + Telemetry\MemoryUsage::fromBytes(2000), + Duration::fromSecondsAndNanoseconds(234, 567), + Telemetry\MemoryUsage::fromBytes(3000), + ); + } + + final protected function testValueObject(): Code\TestMethod + { + return new Code\TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } + + final protected function testSuiteValueObject(): TestSuiteWithName + { + return new TestSuiteWithName( + 'foo', + 9001, + TestCollection::fromArray([]), + ); + } +} diff --git a/tests/unit/Event/Dispatcher/CollectingDispatcherTest.php b/tests/unit/Event/Dispatcher/CollectingDispatcherTest.php new file mode 100644 index 00000000000..35d8b9e10a1 --- /dev/null +++ b/tests/unit/Event/Dispatcher/CollectingDispatcherTest.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(CollectingDispatcher::class)] +#[Small] +final class CollectingDispatcherTest extends TestCase +{ + public function testHasNoCollectedEventsWhenFlushedImmediatelyAfterCreation(): void + { + $typeMap = new TypeMap; + $typeMap->addMapping(Test\DeprecationTriggeredSubscriber::class, Test\DeprecationTriggered::class); + + $dispatcher = new CollectingDispatcher(new DirectDispatcher($typeMap)); + + $this->assertEmpty($dispatcher->flush()); + } + + public function testCollectsDispatchedEventsUntilFlushed(): void + { + $typeMap = new TypeMap; + $typeMap->addMapping(Test\DeprecationTriggeredSubscriber::class, Test\DeprecationTriggered::class); + + $dispatcher = new CollectingDispatcher(new DirectDispatcher($typeMap)); + $event = $this->createStub(Event::class); + + $dispatcher->dispatch($event); + + $this->assertSame([$event], $dispatcher->flush()->asArray()); + } +} diff --git a/tests/unit/Event/Dispatcher/DeferringDispatcherTest.php b/tests/unit/Event/Dispatcher/DeferringDispatcherTest.php new file mode 100644 index 00000000000..1a30b010b40 --- /dev/null +++ b/tests/unit/Event/Dispatcher/DeferringDispatcherTest.php @@ -0,0 +1,84 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\DummySubscriber; + +#[CoversClass(DeferringDispatcher::class)] +#[Small] +final class DeferringDispatcherTest extends TestCase +{ + public function testCollectsEventsUntilFlush(): void + { + $subscribableDispatcher = $this->createMock(SubscribableDispatcher::class); + + $subscribableDispatcher + ->expects($this->never()) + ->method('dispatch'); + + $deferringDispatcher = new DeferringDispatcher($subscribableDispatcher); + + $deferringDispatcher->dispatch($this->createStub(Event::class)); + } + + public function testFlushesCollectedEvents(): void + { + $event = $this->createStub(Event::class); + + $subscribableDispatcher = $this->createMock(SubscribableDispatcher::class); + + $subscribableDispatcher + ->expects($this->once()) + ->method('dispatch') + ->with($this->identicalTo($event)); + + $deferringDispatcher = new DeferringDispatcher($subscribableDispatcher); + + $deferringDispatcher->dispatch($event); + + $deferringDispatcher->flush(); + } + + public function testSubscriberCanBeRegistered(): void + { + $subscriber = $this->createMock(DummySubscriber::class); + + $subscribableDispatcher = $this->createMock(SubscribableDispatcher::class); + + $subscribableDispatcher + ->expects($this->once()) + ->method('registerSubscriber') + ->with($this->identicalTo($subscriber)); + + $deferringDispatcher = new DeferringDispatcher($subscribableDispatcher); + + $deferringDispatcher->registerSubscriber($subscriber); + } + + public function testTracerCanBeRegistered(): void + { + $tracer = $this->createStub(Tracer::class); + + $subscribableDispatcher = $this->createMock(SubscribableDispatcher::class); + + $subscribableDispatcher + ->expects($this->once()) + ->method('registerTracer') + ->with($this->identicalTo($tracer)); + + $deferringDispatcher = new DeferringDispatcher($subscribableDispatcher); + + $deferringDispatcher->registerTracer($tracer); + } +} diff --git a/tests/unit/Event/Dispatcher/DirectDispatcherTest.php b/tests/unit/Event/Dispatcher/DirectDispatcherTest.php new file mode 100644 index 00000000000..220efcbedcb --- /dev/null +++ b/tests/unit/Event/Dispatcher/DirectDispatcherTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\DummyEvent; +use PHPUnit\TestFixture\DummySubscriber; +use RuntimeException; + +#[CoversClass(DirectDispatcher::class)] +#[Small] +final class DirectDispatcherTest extends TestCase +{ + public function testDispatchesEventToKnownSubscribers(): void + { + $event = new DummyEvent; + $typeMap = $this->typeMap(); + + $dispatcher = new DirectDispatcher($typeMap); + + $subscriber = $this->createMock(DummySubscriber::class); + + $subscriber + ->expects($this->once()) + ->method('notify') + ->with($this->identicalTo($event)); + + $dispatcher->registerSubscriber($subscriber); + + $dispatcher->dispatch($event); + } + + public function testDispatchesEventToTracers(): void + { + $event = new DummyEvent; + $typeMap = $this->typeMap(); + + $dispatcher = new DirectDispatcher($typeMap); + + $tracer = $this->createMock(Tracer::class); + + $tracer + ->expects($this->once()) + ->method('trace') + ->with($this->identicalTo($event)); + + $dispatcher->registerTracer($tracer); + + $dispatcher->dispatch($event); + } + + public function testRegisterRejectsUnknownSubscriber(): void + { + $subscriber = $this->createStub(Subscriber::class); + + $dispatcher = new DirectDispatcher(new TypeMap); + + $this->expectException(RuntimeException::class); + + $dispatcher->registerSubscriber($subscriber); + } + + public function testDispatchRejectsUnknownEventType(): void + { + $event = new DummyEvent; + + $dispatcher = new DirectDispatcher(new TypeMap); + + $this->expectException(RuntimeException::class); + + $dispatcher->dispatch($event); + } + + private function typeMap(): TypeMap + { + $typeMap = new TypeMap; + + $typeMap->addMapping(DummySubscriber::class, DummyEvent::class); + + return $typeMap; + } +} diff --git a/tests/unit/Event/Emitter/DispatchingEmitterTest.php b/tests/unit/Event/Emitter/DispatchingEmitterTest.php new file mode 100644 index 00000000000..a7601af9007 --- /dev/null +++ b/tests/unit/Event/Emitter/DispatchingEmitterTest.php @@ -0,0 +1,3573 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use Exception; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Event\Code\TestCollection; +use PHPUnit\Event\Code\TestDoxBuilder; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\TestMethodBuilder; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Telemetry\SystemGarbageCollectorStatusProvider; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Event\TestRunner\ChildProcessErrored; +use PHPUnit\Event\TestRunner\ChildProcessErroredSubscriber; +use PHPUnit\Event\TestRunner\ChildProcessFinished; +use PHPUnit\Event\TestRunner\ChildProcessFinishedSubscriber; +use PHPUnit\Event\TestRunner\ChildProcessStarted; +use PHPUnit\Event\TestRunner\ChildProcessStartedSubscriber; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\DeprecationTriggeredSubscriber as TestRunnerDeprecationTriggeredSubscriber; +use PHPUnit\Event\TestRunner\ExecutionAborted; +use PHPUnit\Event\TestRunner\ExecutionAbortedSubscriber; +use PHPUnit\Event\TestRunner\ExecutionFinished; +use PHPUnit\Event\TestRunner\ExecutionFinishedSubscriber; +use PHPUnit\Event\TestRunner\ExecutionStarted; +use PHPUnit\Event\TestRunner\ExecutionStartedSubscriber; +use PHPUnit\Event\TestRunner\GarbageCollectionDisabled; +use PHPUnit\Event\TestRunner\GarbageCollectionDisabledSubscriber; +use PHPUnit\Event\TestRunner\GarbageCollectionEnabled; +use PHPUnit\Event\TestRunner\GarbageCollectionEnabledSubscriber; +use PHPUnit\Event\TestRunner\GarbageCollectionTriggered; +use PHPUnit\Event\TestRunner\GarbageCollectionTriggeredSubscriber; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggeredSubscriber as TestRunnerNoticeTriggeredSubscriber; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestRunner\WarningTriggeredSubscriber as TestRunnerWarningTriggeredSubscriber; +use PHPUnit\Event\TestSuite\Filtered as TestSuiteFiltered; +use PHPUnit\Event\TestSuite\FilteredSubscriber as TestSuiteFilteredSubscriber; +use PHPUnit\Event\TestSuite\Finished as TestSuiteFinished; +use PHPUnit\Event\TestSuite\FinishedSubscriber as TestSuiteFinishedSubscriber; +use PHPUnit\Event\TestSuite\Loaded as TestSuiteLoaded; +use PHPUnit\Event\TestSuite\LoadedSubscriber as TestSuiteLoadedSubscriber; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Event\TestSuite\SkippedSubscriber as TestSuiteSkippedSubscriber; +use PHPUnit\Event\TestSuite\Sorted as TestSuiteSorted; +use PHPUnit\Event\TestSuite\SortedSubscriber as TestSuiteSortedSubscriber; +use PHPUnit\Event\TestSuite\Started as TestSuiteStarted; +use PHPUnit\Event\TestSuite\StartedSubscriber as TestSuiteStartedSubscriber; +use PHPUnit\Event\TestSuite\TestSuiteWithName; +use PHPUnit\Framework; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\TestFixture\RecordingSubscriber; +use PHPUnit\TextUI\CliArguments\Builder; +use PHPUnit\TextUI\Configuration\Merger; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; + +#[CoversClass(DispatchingEmitter::class)] +#[Small] +final class DispatchingEmitterTest extends Framework\TestCase +{ + #[TestDox('applicationStarted() emits Application\Started event')] + public function testApplicationStartedEmitsApplicationStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Application\StartedSubscriber + { + public function notify(Application\Started $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Application\StartedSubscriber::class, + Application\Started::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->applicationStarted(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(Application\Started::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerStartedStaticAnalysisForCodeCoverage() emits TestRunner\StaticAnalysisForCodeCoverageStarted event')] + public function testTestRunnerStartedStaticAnalysisForCodeCoverageDispatchesStaticAnalysisForCodeCoverageStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\StaticAnalysisForCodeCoverageStartedSubscriber + { + public function notify(TestRunner\StaticAnalysisForCodeCoverageStarted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\StaticAnalysisForCodeCoverageStartedSubscriber::class, + TestRunner\StaticAnalysisForCodeCoverageStarted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerStartedStaticAnalysisForCodeCoverage(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestRunner\StaticAnalysisForCodeCoverageStarted::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerFinishedStaticAnalysisForCodeCoverage() emits TestRunner\StaticAnalysisForCodeCoverageFinished event')] + public function testTestRunnerFinishedStaticAnalysisForCodeCoverageDispatchesStaticAnalysisForCodeCoverageFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\StaticAnalysisForCodeCoverageFinishedSubscriber + { + public function notify(TestRunner\StaticAnalysisForCodeCoverageFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\StaticAnalysisForCodeCoverageFinishedSubscriber::class, + TestRunner\StaticAnalysisForCodeCoverageFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $cacheHits = 1; + $cacheMisses = 2; + + $emitter->testRunnerFinishedStaticAnalysisForCodeCoverage($cacheHits, $cacheMisses); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunner\StaticAnalysisForCodeCoverageFinished::class, $event); + + $this->assertSame($cacheHits, $event->cacheHits()); + $this->assertSame($cacheMisses, $event->cacheMisses()); + } + + #[TestDox('testRunnerStarted() emits TestRunner\Started event')] + public function testTestRunnerStartedEmitsTestRunnerStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\StartedSubscriber + { + public function notify(TestRunner\Started $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\StartedSubscriber::class, + TestRunner\Started::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerStarted(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestRunner\Started::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerConfigured() emits TestRunner\Configured event')] + public function testTestRunnerConfiguredEmitsTestRunnerConfiguredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\ConfiguredSubscriber + { + public function notify(TestRunner\Configured $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\ConfiguredSubscriber::class, + TestRunner\Configured::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $configuration = (new Merger)->merge( + (new Builder)->fromParameters([]), + DefaultConfiguration::create(), + ); + + $emitter->testRunnerConfigured($configuration); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunner\Configured::class, $event); + $this->assertSame($configuration, $event->configuration()); + } + + #[TestDox('bootstrapFinished() emits TestRunner\BootstrapFinished event')] + public function testBootstrapFinishedEmitsBootstrapFinishedEvent(): void + { + $filename = __FILE__; + + $subscriber = new class extends RecordingSubscriber implements TestRunner\BootstrapFinishedSubscriber + { + public function notify(TestRunner\BootstrapFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\BootstrapFinishedSubscriber::class, + TestRunner\BootstrapFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerBootstrapFinished($filename); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunner\BootstrapFinished::class, $event); + + $this->assertSame($filename, $event->filename()); + } + + #[TestDox('testRunnerLoadedExtensionFromPhar() emits TestRunner\ExtensionLoadedFromPhar event')] + public function testTestRunnerLoadedExtensionFromPharEmitsExtensionLoadedFromPharEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\ExtensionLoadedFromPharSubscriber + { + public function notify(TestRunner\ExtensionLoadedFromPhar $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\ExtensionLoadedFromPharSubscriber::class, + TestRunner\ExtensionLoadedFromPhar::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerLoadedExtensionFromPhar( + 'filename', + 'example-extension', + '1.2.3', + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestRunner\ExtensionLoadedFromPhar::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerBootstrappedExtension() emits TestRunner\ExtensionBootstrapped event')] + public function testTestRunnerBootstrappedExtensionEmitsExtensionBootstrappedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\ExtensionBootstrappedSubscriber + { + public function notify(TestRunner\ExtensionBootstrapped $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\ExtensionBootstrappedSubscriber::class, + TestRunner\ExtensionBootstrapped::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $className = 'the-extension'; + $parameters = ['foo' => 'bar']; + + $emitter->testRunnerBootstrappedExtension($className, $parameters); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunner\ExtensionBootstrapped::class, $event); + $this->assertSame($className, $event->className()); + $this->assertSame($parameters, $event->parameters()); + } + + #[TestDox('dataProviderMethodCalled() emits Test\DataProviderMethodCalled event')] + public function testDataProviderMethodCalledEmitsDataProviderMethodCalledEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\DataProviderMethodCalledSubscriber + { + public function notify(Test\DataProviderMethodCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\DataProviderMethodCalledSubscriber::class, + Test\DataProviderMethodCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = new ClassMethod('test-class', 'test-method'); + $dataProviderMethod = new ClassMethod('test-class', 'data-provider-method'); + + $emitter->dataProviderMethodCalled($testMethod, $dataProviderMethod); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\DataProviderMethodCalled::class, $event); + $this->assertSame($testMethod, $event->testMethod()); + $this->assertSame($dataProviderMethod, $event->dataProviderMethod()); + } + + #[TestDox('dataProviderMethodFinished() emits Test\DataProviderMethodFinished event')] + public function testDataProviderMethodFinishedEmitsDataProviderMethodFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\DataProviderMethodFinishedSubscriber + { + public function notify(Test\DataProviderMethodFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\DataProviderMethodFinishedSubscriber::class, + Test\DataProviderMethodFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = new ClassMethod('test-class', 'test-method'); + $dataProviderMethod = new ClassMethod('test-class', 'data-provider-method'); + + $emitter->dataProviderMethodFinished($testMethod, $dataProviderMethod); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\DataProviderMethodFinished::class, $event); + $this->assertSame($testMethod, $event->testMethod()); + $this->assertSame([$dataProviderMethod], $event->calledMethods()); + } + + #[TestDox('testSuiteLoaded() emits TestSuite\Loaded event')] + public function testTestSuiteLoadedEmitsTestSuiteLoadedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestSuiteLoadedSubscriber + { + public function notify(TestSuiteLoaded $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteLoadedSubscriber::class, + TestSuiteLoaded::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testSuiteLoaded($this->testSuiteValueObject()); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestSuiteLoaded::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testSuiteFiltered() emits TestSuite\Filtered event')] + public function testTestSuiteFilteredEmitsTestSuiteFilteredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestSuiteFilteredSubscriber + { + public function notify(TestSuiteFiltered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteFilteredSubscriber::class, + TestSuiteFiltered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testSuite = $this->testSuiteValueObject(); + + $emitter->testSuiteFiltered($testSuite); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestSuiteFiltered::class, $event); + + $this->assertSame($testSuite, $event->testSuite()); + } + + #[TestDox('testSuiteSorted() emits TestSuite\Sorted event')] + public function testTestSuiteSortedEmitsTestSuiteSortedEvent(): void + { + $executionOrder = 9001; + $executionOrderDefects = 5; + $resolveDependencies = true; + + $subscriber = new class extends RecordingSubscriber implements TestSuiteSortedSubscriber + { + public function notify(TestSuiteSorted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteSortedSubscriber::class, + TestSuiteSorted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testSuiteSorted( + $executionOrder, + $executionOrderDefects, + $resolveDependencies, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestSuiteSorted::class, $event); + + $this->assertSame($executionOrder, $event->executionOrder()); + $this->assertSame($executionOrderDefects, $event->executionOrderDefects()); + $this->assertSame($resolveDependencies, $event->resolveDependencies()); + } + + #[TestDox('testRunnerEventFacadeSealed() emits TestRunner\EventFacadeSealed event')] + public function testTestRunnerEventFacadeSealedEmitsTestRunnerEventFacadeSealedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\EventFacadeSealedSubscriber + { + public function notify(TestRunner\EventFacadeSealed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\EventFacadeSealedSubscriber::class, + TestRunner\EventFacadeSealed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerEventFacadeSealed(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestRunner\EventFacadeSealed::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerExecutionStarted() emits TestRunner\ExecutionStarted event')] + public function testTestRunnerExecutionStartedEmitsTestRunnerExecutionStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ExecutionStartedSubscriber + { + public function notify(ExecutionStarted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ExecutionStartedSubscriber::class, + ExecutionStarted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testSuite = $this->testSuiteValueObject(); + + $emitter->testRunnerExecutionStarted($testSuite); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(ExecutionStarted::class, $event); + $this->assertSame($testSuite, $event->testSuite()); + } + + #[TestDox('testRunnerDisabledGarbageCollection() emits TestRunner\GarbageCollectionDisabled event')] + public function testTestRunnerDisabledGarbageCollectionEmitsTestRunnerGarbageCollectionDisabledEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements GarbageCollectionDisabledSubscriber + { + public function notify(GarbageCollectionDisabled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + GarbageCollectionDisabledSubscriber::class, + GarbageCollectionDisabled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerDisabledGarbageCollection(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(GarbageCollectionDisabled::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerTriggeredGarbageCollection() emits TestRunner\GarbageCollectionTriggered event')] + public function testTestRunnerTriggeredGarbageCollectionEmitsTestRunnerGarbageCollectionTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements GarbageCollectionTriggeredSubscriber + { + public function notify(GarbageCollectionTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + GarbageCollectionTriggeredSubscriber::class, + GarbageCollectionTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerTriggeredGarbageCollection(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(GarbageCollectionTriggered::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('childProcessStarted() emits TestRunner\ChildProcessStarted event')] + public function testChildProcessStartedEmitsTestRunnerChildProcessStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ChildProcessStartedSubscriber + { + public function notify(ChildProcessStarted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ChildProcessStartedSubscriber::class, + ChildProcessStarted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->childProcessStarted(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(ChildProcessStarted::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('childProcessErrored() emits TestRunner\ChildProcessErrored event')] + public function testChildProcessErroredEmitsTestRunnerChildProcessStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ChildProcessErroredSubscriber + { + public function notify(ChildProcessErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ChildProcessErroredSubscriber::class, + ChildProcessErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->childProcessErrored(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(ChildProcessErrored::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('childProcessFinished() emits TestRunner\ChildProcessFinished event')] + public function testChildProcessFinishedEmitsTestRunnerChildProcessFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ChildProcessFinishedSubscriber + { + public function notify(ChildProcessFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ChildProcessFinishedSubscriber::class, + ChildProcessFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $stdout = 'stdout'; + $stderr = 'stderr'; + + $emitter->childProcessFinished($stdout, $stderr); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(ChildProcessFinished::class, $event); + $this->assertSame($stdout, $event->stdout()); + $this->assertSame($stderr, $event->stderr()); + } + + #[TestDox('testSuiteSkipped() emits TestSuite\Skipped event')] + public function testTestSuiteSkippedEmitsTestSuiteSkippedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestSuiteSkippedSubscriber + { + public function notify(TestSuiteSkipped $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteSkippedSubscriber::class, + TestSuiteSkipped::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testSuite = $this->testSuiteValueObject(); + $message = 'message'; + + $emitter->testSuiteSkipped($testSuite, $message); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestSuiteSkipped::class, $event); + $this->assertSame($testSuite, $event->testSuite()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testSuiteStarted() emits TestSuite\Started event')] + public function testTestSuiteStartedEmitsTestSuiteStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestSuiteStartedSubscriber + { + public function notify(TestSuiteStarted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteStartedSubscriber::class, + TestSuiteStarted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testSuite = $this->testSuiteValueObject(); + + $emitter->testSuiteStarted($testSuite); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestSuiteStarted::class, $event); + $this->assertSame($testSuite, $event->testSuite()); + } + + #[TestDox('testPreparationStarted() emits Test\PreparationStarted event')] + public function testTestPreparationStartedEmitsTestPreparationStartedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreparationStartedSubscriber + { + public function notify(Test\PreparationStarted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreparationStartedSubscriber::class, + Test\PreparationStarted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + + $emitter->testPreparationStarted($test); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreparationStarted::class, $event); + $this->assertSame($test, $event->test()); + } + + #[TestDox('testPreparationErrored() emits Test\PreparationErrored event')] + public function testTestPreparationErroredEmitsTestPreparationErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreparationErroredSubscriber + { + public function notify(Test\PreparationErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreparationErroredSubscriber::class, + Test\PreparationErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->testPreparationErrored($test, $throwable); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreparationErrored::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('testPreparationFailed() emits Test\PreparationFailed event')] + public function testTestPreparationFailedEmitsTestPreparationFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreparationFailedSubscriber + { + public function notify(Test\PreparationFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreparationFailedSubscriber::class, + Test\PreparationFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->testPreparationFailed($test, $throwable); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreparationFailed::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('beforeFirstTestMethodCalled() emits Test\BeforeFirstTestMethodCalled event')] + public function testTestBeforeFirstTestMethodCalledEmitsTestBeforeFirstTestMethodEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeFirstTestMethodCalledSubscriber + { + public function notify(Test\BeforeFirstTestMethodCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeFirstTestMethodCalledSubscriber::class, + Test\BeforeFirstTestMethodCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->beforeFirstTestMethodCalled( + $testClassName, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeFirstTestMethodCalled::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('beforeFirstTestMethodErrored() emits Test\BeforeFirstTestMethodErrored event')] + public function testTestBeforeFirstTestMethodErroredEmitsTestBeforeFirstTestMethodErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeFirstTestMethodErroredSubscriber + { + public function notify(Test\BeforeFirstTestMethodErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeFirstTestMethodErroredSubscriber::class, + Test\BeforeFirstTestMethodErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->beforeFirstTestMethodErrored( + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeFirstTestMethodErrored::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('beforeFirstTestMethodFailed() emits Test\BeforeFirstTestMethodFailed event')] + public function testTestBeforeFirstTestMethodFailedEmitsTestBeforeFirstTestMethodFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeFirstTestMethodFailedSubscriber + { + public function notify(Test\BeforeFirstTestMethodFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeFirstTestMethodFailedSubscriber::class, + Test\BeforeFirstTestMethodFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->beforeFirstTestMethodFailed( + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeFirstTestMethodFailed::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('beforeFirstTestMethodFinished() emits Test\BeforeFirstTestMethodFinished event')] + public function testTestBeforeFirstTestMethodFinishedEmitsTestBeforeFirstTestMethodFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeFirstTestMethodFinishedSubscriber + { + public function notify(Test\BeforeFirstTestMethodFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeFirstTestMethodFinishedSubscriber::class, + Test\BeforeFirstTestMethodFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->beforeFirstTestMethodFinished( + $testClassName, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeFirstTestMethodFinished::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('beforeTestMethodCalled() emits Test\BeforeTestMethodCalled event')] + public function testTestBeforeTestMethodCalledEmitsTestBeforeTestMethodEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeTestMethodCalledSubscriber + { + public function notify(Test\BeforeTestMethodCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeTestMethodCalledSubscriber::class, + Test\BeforeTestMethodCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->beforeTestMethodCalled( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeTestMethodCalled::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('beforeTestMethodErrored() emits Test\BeforeTestMethodErrored event')] + public function testTestBeforeTestMethodErroredEmitsTestBeforeTestMethodErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeTestMethodErroredSubscriber + { + public function notify(Test\BeforeTestMethodErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeTestMethodErroredSubscriber::class, + Test\BeforeTestMethodErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->beforeTestMethodErrored( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeTestMethodErrored::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('beforeTestMethodFailed() emits Test\BeforeTestMethodFailed event')] + public function testTestBeforeTestMethodFailedEmitsTestBeforeTestMethodFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeTestMethodFailedSubscriber + { + public function notify(Test\BeforeTestMethodFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeTestMethodFailedSubscriber::class, + Test\BeforeTestMethodFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->beforeTestMethodFailed( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeTestMethodFailed::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('beforeTestMethodFinished() emits Test\BeforeTestMethodFinished event')] + public function testTestBeforeTestMethodFinishedEmitsTestBeforeTestMethodFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\BeforeTestMethodFinishedSubscriber + { + public function notify(Test\BeforeTestMethodFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\BeforeTestMethodFinishedSubscriber::class, + Test\BeforeTestMethodFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->beforeTestMethodFinished( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\BeforeTestMethodFinished::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('preConditionCalled() emits Test\PreConditionCalled event')] + public function testPreConditionCalledEmitsTestPreConditionCalledEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreConditionCalledSubscriber + { + public function notify(Test\PreConditionCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreConditionCalledSubscriber::class, + Test\PreConditionCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->preConditionCalled( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreConditionCalled::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('preConditionErrored() emits Test\PreConditionErrored event')] + public function testPreConditionErroredEmitsTestPreConditionErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreConditionErroredSubscriber + { + public function notify(Test\PreConditionErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreConditionErroredSubscriber::class, + Test\PreConditionErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->preConditionErrored( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreConditionErrored::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('preConditionFailed() emits Test\PreConditionFailed event')] + public function testPreConditionFailedEmitsTestPreConditionFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreConditionFailedSubscriber + { + public function notify(Test\PreConditionFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreConditionFailedSubscriber::class, + Test\PreConditionFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->preConditionFailed( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreConditionFailed::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('preConditionFinished() emits Test\PreConditionFinished event')] + public function testPreConditionFinishedEmitsTestPreConditionFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreConditionFinishedSubscriber + { + public function notify(Test\PreConditionFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreConditionFinishedSubscriber::class, + Test\PreConditionFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->preConditionFinished( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PreConditionFinished::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('testPrepared() emits Test\Prepared event')] + public function testTestPreparedEmitsTestPreparedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PreparedSubscriber + { + public function notify(Test\Prepared $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PreparedSubscriber::class, + Test\Prepared::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + + $emitter->testPrepared($test); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Prepared::class, $event); + + $this->assertSame($test, $event->test()); + } + + #[TestDox('testRegisteredComparator() emits Test\ComparatorRegistered event')] + public function testComparatorRegisteredEmitsComparatorRegisteredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\ComparatorRegisteredSubscriber + { + public function notify(Test\ComparatorRegistered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\ComparatorRegisteredSubscriber::class, + Test\ComparatorRegistered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $className = 'the-class'; + + $emitter->testRegisteredComparator($className); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\ComparatorRegistered::class, $event); + + $this->assertSame($className, $event->className()); + } + + #[TestDox('testUsedCustomMethodInvocation() emits Test\CustomTestMethodInvocationUsed event')] + public function testUsedCustomMethodInvocationEmitsCustomTestMethodInvocationUsed(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\CustomTestMethodInvocationUsedSubscriber + { + public function notify(Test\CustomTestMethodInvocationUsed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\CustomTestMethodInvocationUsedSubscriber::class, + Test\CustomTestMethodInvocationUsed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testMethod(); + $customTestMethodInvocation = new ClassMethod('ExampleTest', 'invokeTestMethod'); + + $emitter->testUsedCustomMethodInvocation( + $test, + $customTestMethodInvocation, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\CustomTestMethodInvocationUsed::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($customTestMethodInvocation, $event->customTestMethodInvocation()); + } + + #[TestDox('testCreatedMockObject() emits Test\MockObjectCreated event')] + public function testTestCreatedMockObjectEmitsTestMockObjectCreatedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\MockObjectCreatedSubscriber + { + public function notify(Test\MockObjectCreated $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\MockObjectCreatedSubscriber::class, + Test\MockObjectCreated::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $className = 'the-class'; + + $emitter->testCreatedMockObject($className); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\MockObjectCreated::class, $event); + + $this->assertSame($className, $event->className()); + } + + #[TestDox('testCreatedMockObjectForIntersectionOfInterfaces() emits Test\MockObjectForIntersectionOfInterfacesCreated event')] + public function testTestCreatedMockObjectForIntersectionOfInterfacesEmitsTestMockObjectForIntersectionOfInterfacesCreatedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\MockObjectForIntersectionOfInterfacesCreatedSubscriber + { + public function notify(Test\MockObjectForIntersectionOfInterfacesCreated $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\MockObjectForIntersectionOfInterfacesCreatedSubscriber::class, + Test\MockObjectForIntersectionOfInterfacesCreated::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $interfaces = ['a', 'b']; + + $emitter->testCreatedMockObjectForIntersectionOfInterfaces($interfaces); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\MockObjectForIntersectionOfInterfacesCreated::class, $event); + + $this->assertSame($interfaces, $event->interfaces()); + } + + #[TestDox('testCreatedPartialMockObject() emits Test\PartialMockObjectCreated event')] + public function testTestCreatedPartialMockObjectEmitsTestPartialMockObjectCreatedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PartialMockObjectCreatedSubscriber + { + public function notify(Test\PartialMockObjectCreated $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PartialMockObjectCreatedSubscriber::class, + Test\PartialMockObjectCreated::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $className = 'the-class'; + $methodNames = ['foo', 'bar', 'baz']; + + $emitter->testCreatedPartialMockObject( + $className, + ...$methodNames, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PartialMockObjectCreated::class, $event); + + $this->assertSame($className, $event->className()); + $this->assertSame($methodNames, $event->methodNames()); + } + + #[TestDox('testCreatedStub() emits Test\TestStubCreated event')] + public function testTestStubCreatedEmitsTestTestStubCreatedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\TestStubCreatedSubscriber + { + public function notify(Test\TestStubCreated $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\TestStubCreatedSubscriber::class, + Test\TestStubCreated::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $className = 'the-class'; + + $emitter->testCreatedStub($className); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\TestStubCreated::class, $event); + + $this->assertSame($className, $event->className()); + } + + #[TestDox('testCreatedStubForIntersectionOfInterfaces() emits Test\TestStubForIntersectionOfInterfacesCreated event')] + public function testTestCreatedTestStubForIntersectionOfInterfacesEmitsTestTestStubForIntersectionOfInterfacesCreatedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\TestStubForIntersectionOfInterfacesCreatedSubscriber + { + public function notify(Test\TestStubForIntersectionOfInterfacesCreated $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\TestStubForIntersectionOfInterfacesCreatedSubscriber::class, + Test\TestStubForIntersectionOfInterfacesCreated::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $interfaces = ['a', 'b']; + + $emitter->testCreatedStubForIntersectionOfInterfaces($interfaces); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\TestStubForIntersectionOfInterfacesCreated::class, $event); + + $this->assertSame($interfaces, $event->interfaces()); + } + + #[TestDox('testErrored() emits Test\Errored event')] + public function testTestErroredEmitsTestErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\ErroredSubscriber + { + public function notify(Test\Errored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\ErroredSubscriber::class, + Test\Errored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('error')); + + $emitter->testErrored( + $test, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Errored::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('testFailed() emits Test\Failed event')] + public function testTestFailedEmitsTestFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\FailedSubscriber + { + public function notify(Test\Failed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\FailedSubscriber::class, + Test\Failed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('failure')); + $failure = null; + + $emitter->testFailed( + $test, + $throwable, + $failure, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Failed::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + $this->assertFalse($event->hasComparisonFailure()); + } + + #[TestDox('testPassed() emits Test\Passed event')] + public function testTestPassedEmitsTestPassedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PassedSubscriber + { + public function notify(Test\Passed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PassedSubscriber::class, + Test\Passed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + + $emitter->testPassed($test); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Passed::class, $event); + + $this->assertSame($test, $event->test()); + } + + #[TestDox('testConsideredRisky() emits Test\ConsideredRisky event')] + public function testTestConsideredRiskyEmitsTestConsideredRiskyEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\ConsideredRiskySubscriber + { + public function notify(Test\ConsideredRisky $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\ConsideredRiskySubscriber::class, + Test\ConsideredRisky::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + + $emitter->testConsideredRisky($test, $message); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(Test\ConsideredRisky::class, $subscriber->lastRecordedEvent()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testMarkedAsIncomplete() emits Test\MarkedIncomplete event')] + public function testTestMarkedIncompleteEmitsTestMarkedIncompleteEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\MarkedIncompleteSubscriber + { + public function notify(Test\MarkedIncomplete $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\MarkedIncompleteSubscriber::class, + Test\MarkedIncomplete::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('incomplete')); + + $emitter->testMarkedAsIncomplete( + $test, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\MarkedIncomplete::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('testSkipped() emits Test\Skipped event')] + public function testTestSkippedEmitsTestSkippedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\SkippedSubscriber + { + public function notify(Test\Skipped $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\SkippedSubscriber::class, + Test\Skipped::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'skipped'; + + $emitter->testSkipped( + $test, + $message, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Skipped::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testTriggeredPhpunitDeprecation() emits Test\PhpunitDeprecationTriggered event')] + public function testTestTriggeredPhpunitDeprecationEmitsTestPhpunitDeprecationTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpunitDeprecationTriggeredSubscriber + { + public function notify(Test\PhpunitDeprecationTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpunitDeprecationTriggeredSubscriber::class, + Test\PhpunitDeprecationTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + + $emitter->testTriggeredPhpunitDeprecation( + $test, + $message, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpunitDeprecationTriggered::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testTriggeredPhpunitNotice() emits Test\PhpunitNoticeTriggered event')] + public function testTestTriggeredPhpunitNoticeEmitsTestPhpunitNoticeTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpunitNoticeTriggeredSubscriber + { + public function notify(Test\PhpunitNoticeTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpunitNoticeTriggeredSubscriber::class, + Test\PhpunitNoticeTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + + $emitter->testTriggeredPhpunitNotice( + $test, + $message, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpunitNoticeTriggered::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testTriggeredPhpDeprecation() emits Test\PhpDeprecationTriggered event')] + public function testTestTriggeredPhpDeprecationEmitsTestPhpDeprecationTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpDeprecationTriggeredSubscriber + { + public function notify(Test\PhpDeprecationTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpDeprecationTriggeredSubscriber::class, + Test\PhpDeprecationTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + $ignoredByTest = false; + $trigger = IssueTrigger::unknown(); + + $emitter->testTriggeredPhpDeprecation( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpDeprecationTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame($ignoredByTest, $event->ignoredByTest()); + $this->assertSame($trigger, $event->trigger()); + } + + #[TestDox('testTriggeredDeprecation() emits Test\DeprecationTriggered event')] + public function testTestTriggeredDeprecationEmitsTestDeprecationTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\DeprecationTriggeredSubscriber + { + public function notify(Test\DeprecationTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\DeprecationTriggeredSubscriber::class, + Test\DeprecationTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + $ignoredByTest = false; + $trigger = IssueTrigger::unknown(); + $stackTrace = 'stack-trace'; + + $emitter->testTriggeredDeprecation( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + $stackTrace, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\DeprecationTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame($ignoredByTest, $event->ignoredByTest()); + $this->assertSame($trigger, $event->trigger()); + $this->assertSame($stackTrace, $event->stackTrace()); + } + + #[TestDox('testTriggeredError() emits Test\ErrorTriggered event')] + public function testTestTriggeredErrorEmitsTestErrorTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\ErrorTriggeredSubscriber + { + public function notify(Test\ErrorTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\ErrorTriggeredSubscriber::class, + Test\ErrorTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + + $emitter->testTriggeredError( + $test, + $message, + $file, + $line, + $suppressed, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\ErrorTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + } + + #[TestDox('testTriggeredNotice() emits Test\NoticeTriggered event')] + public function testTestTriggeredNoticeEmitsTestNoticeTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\NoticeTriggeredSubscriber + { + public function notify(Test\NoticeTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\NoticeTriggeredSubscriber::class, + Test\NoticeTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $emitter->testTriggeredNotice( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\NoticeTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + } + + #[TestDox('testTriggeredPhpNotice() emits Test\PhpNoticeTriggered event')] + public function testTestTriggeredPhpNoticeEmitsTestPhpNoticeTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpNoticeTriggeredSubscriber + { + public function notify(Test\PhpNoticeTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpNoticeTriggeredSubscriber::class, + Test\PhpNoticeTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $emitter->testTriggeredPhpNotice( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpNoticeTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + } + + #[TestDox('testTriggeredWarning() emits Test\WarningTriggered event')] + public function testTestTriggeredWarningEmitsTestWarningTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\WarningTriggeredSubscriber + { + public function notify(Test\WarningTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\WarningTriggeredSubscriber::class, + Test\WarningTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $emitter->testTriggeredWarning( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\WarningTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + } + + #[TestDox('testTriggeredPhpWarning() emits Test\PhpWarningTriggered event')] + public function testTestTriggeredPhpWarningEmitsTestPhpWarningTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpWarningTriggeredSubscriber + { + public function notify(Test\PhpWarningTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpWarningTriggeredSubscriber::class, + Test\PhpWarningTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file.php'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $emitter->testTriggeredPhpWarning( + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpWarningTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + } + + #[TestDox('testTriggeredPhpunitError() emits Test\PhpunitErrorTriggered event')] + public function testTestTriggeredPhpunitErrorEmitsTestPhpunitErrorTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpunitErrorTriggeredSubscriber + { + public function notify(Test\PhpunitErrorTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpunitErrorTriggeredSubscriber::class, + Test\PhpunitErrorTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + $message = 'message'; + + $emitter->testTriggeredPhpunitError( + $test, + $message, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpunitErrorTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + #[TestDox('testTriggeredPhpunitWarning() emits Test\PhpunitWarningTriggered event')] + public function testTestTriggeredPhpunitWarningEmitsTestPhpunitWarningTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PhpunitWarningTriggeredSubscriber + { + public function notify(Test\PhpunitWarningTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PhpunitWarningTriggeredSubscriber::class, + Test\PhpunitWarningTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = TestMethodBuilder::fromTestCase($this); + $message = 'message'; + + $emitter->testTriggeredPhpunitWarning( + $test, + $message, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PhpunitWarningTriggered::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertFalse($event->ignoredByTest()); + } + + #[TestDox('testPrintedUnexpectedOutput() emits Test\PrintedUnexpectedOutput event')] + public function testTestPrintedUnexpectedOutputEmitsTestPrintedUnexpectedOutputEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PrintedUnexpectedOutputSubscriber + { + public function notify(Test\PrintedUnexpectedOutput $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PrintedUnexpectedOutputSubscriber::class, + Test\PrintedUnexpectedOutput::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $output = 'output'; + + $emitter->testPrintedUnexpectedOutput( + $output, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PrintedUnexpectedOutput::class, $event); + $this->assertSame($output, $event->output()); + } + + #[TestDox('testProvidedAdditionalInformation() emits Test\AdditionalInformationProvided event')] + public function testTestProvidedAdditionalInformationEmitsAdditionalInformationProvidedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AdditionalInformationProvidedSubscriber + { + public function notify(Test\AdditionalInformationProvided $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AdditionalInformationProvidedSubscriber::class, + Test\AdditionalInformationProvided::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + $test = $this->testValueObject(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $additionalInformation = 'addtional information'; + + $emitter->testProvidedAdditionalInformation( + $test, + $additionalInformation, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AdditionalInformationProvided::class, $event); + $this->assertSame($test, $event->test()); + $this->assertSame($additionalInformation, $event->additionalInformation()); + } + + #[TestDox('testFinished() emits Test\Finished event')] + public function testTestFinishedEmitsTestFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\FinishedSubscriber + { + public function notify(Test\Finished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\FinishedSubscriber::class, + Test\Finished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $test = $this->testValueObject(); + + $emitter->testFinished($test, 1); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\Finished::class, $event); + + $this->assertSame($test, $event->test()); + $this->assertSame(1, $event->numberOfAssertionsPerformed()); + } + + #[TestDox('postConditionCalled() emits Test\PostConditionCalled event')] + public function testPostConditionCalledEmitsTestPostConditionCalledEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PostConditionCalledSubscriber + { + public function notify(Test\PostConditionCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PostConditionCalledSubscriber::class, + Test\PostConditionCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->postConditionCalled( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PostConditionCalled::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('postConditionErrored() emits Test\PostConditionErrored event')] + public function testPostConditionErroredEmitsTestPostConditionErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PostConditionErroredSubscriber + { + public function notify(Test\PostConditionErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PostConditionErroredSubscriber::class, + Test\PostConditionErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->postConditionErrored( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PostConditionErrored::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('postConditionFailed() emits Test\PostConditionFailed event')] + public function testPostConditionFailedEmitsTestPostConditionFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PostConditionFailedSubscriber + { + public function notify(Test\PostConditionFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PostConditionFailedSubscriber::class, + Test\PostConditionFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->postConditionFailed( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PostConditionFailed::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('postConditionFinished() emits Test\PostConditionFinished event')] + public function testPostConditionFinishedEmitsTestPostConditionFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\PostConditionFinishedSubscriber + { + public function notify(Test\PostConditionFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\PostConditionFinishedSubscriber::class, + Test\PostConditionFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->postConditionFinished( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\PostConditionFinished::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('afterTestMethodCalled() emits Test\AfterTestMethodCalled event')] + public function testTestAfterTestMethodCalledEmitsTestAfterTestMethodEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterTestMethodCalledSubscriber + { + public function notify(Test\AfterTestMethodCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterTestMethodCalledSubscriber::class, + Test\AfterTestMethodCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->afterTestMethodCalled( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterTestMethodCalled::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('afterTestMethodErrored() emits Test\AfterTestMethodErrored event')] + public function testTestAfterTestMethodErroredEmitsTestAfterTestMethodErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterTestMethodErroredSubscriber + { + public function notify(Test\AfterTestMethodErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterTestMethodErroredSubscriber::class, + Test\AfterTestMethodErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->afterTestMethodErrored( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterTestMethodErrored::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('afterTestMethodFailed() emits Test\AfterTestMethodFailed event')] + public function testTestAfterTestMethodFailedEmitsTestAfterTestMethodFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterTestMethodFailedSubscriber + { + public function notify(Test\AfterTestMethodFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterTestMethodFailedSubscriber::class, + Test\AfterTestMethodFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->afterTestMethodFailed( + $testMethod, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterTestMethodFailed::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('afterTestMethodFinished() emits Test\AfterTestMethodFinished event')] + public function testTestAfterTestMethodFinishedEmitsTestAfterTestMethodFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterTestMethodFinishedSubscriber + { + public function notify(Test\AfterTestMethodFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterTestMethodFinishedSubscriber::class, + Test\AfterTestMethodFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testMethod = $this->testMethod(); + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->afterTestMethodFinished( + $testMethod, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterTestMethodFinished::class, $event); + + $this->assertSame($testMethod, $event->test()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('afterLastTestMethodCalled() emits Test\AfterLastTestMethodCalled event')] + public function testTestAfterLastTestMethodCalledEmitsTestAfterLastTestMethodEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterLastTestMethodCalledSubscriber + { + public function notify(Test\AfterLastTestMethodCalled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterLastTestMethodCalledSubscriber::class, + Test\AfterLastTestMethodCalled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->afterLastTestMethodCalled( + $testClassName, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterLastTestMethodCalled::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + #[TestDox('afterLastTestMethodErrored() emits Test\AfterLastTestMethodErrored event')] + public function testTestAfterLastTestMethodErroredEmitsTestAfterLastTestMethodErroredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterLastTestMethodErroredSubscriber + { + public function notify(Test\AfterLastTestMethodErrored $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterLastTestMethodErroredSubscriber::class, + Test\AfterLastTestMethodErrored::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->afterLastTestMethodErrored( + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterLastTestMethodErrored::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('afterLastTestMethodFailed() emits Test\AfterLastTestMethodFailed event')] + public function testTestAfterLastTestMethodFailedEmitsTestAfterLastTestMethodFailedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterLastTestMethodFailedSubscriber + { + public function notify(Test\AfterLastTestMethodFailed $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterLastTestMethodFailedSubscriber::class, + Test\AfterLastTestMethodFailed::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $emitter->afterLastTestMethodFailed( + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterLastTestMethodFailed::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + #[TestDox('afterLastTestMethodFinished() emits Test\AfterLastTestMethodFinished event')] + public function testTestAfterLastTestMethodFinishedEmitsTestAfterLastTestMethodFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Test\AfterLastTestMethodFinishedSubscriber + { + public function notify(Test\AfterLastTestMethodFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Test\AfterLastTestMethodFinishedSubscriber::class, + Test\AfterLastTestMethodFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $testClassName = 'test-class'; + $calledMethod = new ClassMethod('test-class', 'method'); + + $emitter->afterLastTestMethodFinished( + $testClassName, + $calledMethod, + ); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Test\AfterLastTestMethodFinished::class, $event); + + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame([$calledMethod], $event->calledMethods()); + } + + #[TestDox('testSuiteFinished() emits TestSuite\Finished event')] + public function testTestSuiteFinishedEmitsTestSuiteFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestSuiteFinishedSubscriber + { + public function notify(TestSuiteFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestSuiteFinishedSubscriber::class, + TestSuiteFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testSuiteFinished($this->testSuiteValueObject()); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestSuiteFinished::class, $event); + + $this->assertSame('Test Suite', $event->testSuite()->name()); + $this->assertSame(0, $event->testSuite()->count()); + } + + #[TestDox('testRunnerTriggeredPhpunitDeprecation() emits TestRunner\DeprecationTriggered event')] + public function testTestRunnerTriggeredPhpunitDeprecationEmitsTestRunnerDeprecationTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunnerDeprecationTriggeredSubscriber + { + public function notify(TestRunnerDeprecationTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunnerDeprecationTriggeredSubscriber::class, + TestRunnerDeprecationTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $message = 'message'; + + $emitter->testRunnerTriggeredPhpunitDeprecation($message); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunnerDeprecationTriggered::class, $event); + + $this->assertSame($message, $event->message()); + } + + #[TestDox('testRunnerTriggeredPhpunitNotice() emits TestRunner\NoticeTriggered event')] + public function testTestRunnerTriggeredPhpunitNoticeEmitsTestRunnerNoticeTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunnerNoticeTriggeredSubscriber + { + public function notify(TestRunnerNoticeTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunnerNoticeTriggeredSubscriber::class, + TestRunnerNoticeTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $message = 'message'; + + $emitter->testRunnerTriggeredPhpunitNotice($message); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunnerNoticeTriggered::class, $event); + + $this->assertSame($message, $event->message()); + } + + #[TestDox('testRunnerTriggeredPhpunitWarning() emits TestRunner\WarningTriggered event')] + public function testTestRunnerTriggeredPhpunitWarningEmitsTestRunnerWarningTriggeredEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunnerWarningTriggeredSubscriber + { + public function notify(TestRunnerWarningTriggered $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunnerWarningTriggeredSubscriber::class, + TestRunnerWarningTriggered::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $message = 'message'; + + $emitter->testRunnerTriggeredPhpunitWarning($message); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(TestRunnerWarningTriggered::class, $event); + + $this->assertSame($message, $event->message()); + } + + #[TestDox('testRunnerEnabledGarbageCollection() emits TestRunner\GarbageCollectionEnabled event')] + public function testTestRunnerEnabledGarbageCollectionEmitsTestRunnerGarbageCollectionEnabledEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements GarbageCollectionEnabledSubscriber + { + public function notify(GarbageCollectionEnabled $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + GarbageCollectionEnabledSubscriber::class, + GarbageCollectionEnabled::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerEnabledGarbageCollection(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(GarbageCollectionEnabled::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerExecutionAborted() emits TestRunner\ExecutionAborted event')] + public function testTestRunnerExecutionAbortedEmitsTestRunnerExecutionAbortedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ExecutionAbortedSubscriber + { + public function notify(ExecutionAborted $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ExecutionAbortedSubscriber::class, + ExecutionAborted::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerExecutionAborted(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(ExecutionAborted::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerExecutionFinished() emits TestRunner\ExecutionFinished event')] + public function testTestRunnerExecutionFinishedEmitsTestRunnerExecutionFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements ExecutionFinishedSubscriber + { + public function notify(ExecutionFinished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + ExecutionFinishedSubscriber::class, + ExecutionFinished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerExecutionFinished(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(ExecutionFinished::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('testRunnerFinished() emits TestRunner\Finished event')] + public function testTestRunnerFinishedEmitsTestRunnerFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements TestRunner\FinishedSubscriber + { + public function notify(TestRunner\Finished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + TestRunner\FinishedSubscriber::class, + TestRunner\Finished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $emitter->testRunnerFinished(); + + $this->assertSame(1, $subscriber->recordedEventCount()); + $this->assertInstanceOf(TestRunner\Finished::class, $subscriber->lastRecordedEvent()); + } + + #[TestDox('applicationFinished() emits Application\Finished event')] + public function testApplicationFinishedEmitsApplicationFinishedEvent(): void + { + $subscriber = new class extends RecordingSubscriber implements Application\FinishedSubscriber + { + public function notify(Application\Finished $event): void + { + $this->record($event); + } + }; + + $dispatcher = $this->dispatcherWithRegisteredSubscriber( + Application\FinishedSubscriber::class, + Application\Finished::class, + $subscriber, + ); + + $telemetrySystem = $this->telemetrySystem(); + + $emitter = new DispatchingEmitter( + $dispatcher, + $telemetrySystem, + ); + + $shellExitCode = 0; + + $emitter->applicationFinished($shellExitCode); + + $this->assertSame(1, $subscriber->recordedEventCount()); + + $event = $subscriber->lastRecordedEvent(); + + $this->assertInstanceOf(Application\Finished::class, $event); + $this->assertSame($shellExitCode, $event->shellExitCode()); + } + + private function testSuiteValueObject(): TestSuiteWithName + { + return new TestSuiteWithName( + 'Test Suite', + 0, + TestCollection::fromArray([]), + ); + } + + private function dispatcherWithRegisteredSubscriber(string $subscriberInterface, string $eventClass, Subscriber $subscriber): DirectDispatcher + { + $typeMap = new TypeMap; + + $typeMap->addMapping( + $subscriberInterface, + $eventClass, + ); + + $dispatcher = new DirectDispatcher($typeMap); + + $dispatcher->registerSubscriber($subscriber); + + return $dispatcher; + } + + private function telemetrySystem(): Telemetry\System + { + return new Telemetry\System( + new Telemetry\SystemStopWatch, + new Telemetry\SystemMemoryMeter, + new SystemGarbageCollectorStatusProvider, + ); + } + + private function testValueObject(): TestMethod + { + return new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } + + private function testMethod(): TestMethod + { + return new TestMethod( + 'TestClass', + 'testMethod', + 'TestClass.php', + 1, + new Code\TestDox('', '', ''), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } +} diff --git a/tests/unit/Event/EventCollectionTest.php b/tests/unit/Event/EventCollectionTest.php new file mode 100644 index 00000000000..47e8b340d18 --- /dev/null +++ b/tests/unit/Event/EventCollectionTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(EventCollection::class)] +#[CoversClass(EventCollectionIterator::class)] +#[Small] +final class EventCollectionTest extends TestCase +{ + public function testIsInitiallyEmpty(): void + { + $events = new EventCollection; + + $this->assertEmpty($events); + $this->assertTrue($events->isEmpty()); + $this->assertFalse($events->isNotEmpty()); + $this->assertSame([], $events->asArray()); + } + + public function testCollectsEventObjects(): void + { + $event = $this->createStub(Event::class); + $events = new EventCollection; + + $events->add($event); + + $this->assertNotEmpty($events); + $this->assertTrue($events->isNotEmpty()); + $this->assertFalse($events->isEmpty()); + $this->assertSame([$event], $events->asArray()); + } + + public function testCanBeIterated(): void + { + $event = $this->createStub(Event::class); + $events = new EventCollection; + + $events->add($event); + + foreach ($events as $index => $_event) { + $this->assertSame(0, $index); + $this->assertSame($event, $_event); + } + } +} diff --git a/tests/unit/Event/Events/Application/FinishedTest.php b/tests/unit/Event/Events/Application/FinishedTest.php new file mode 100644 index 00000000000..eabf1f52b33 --- /dev/null +++ b/tests/unit/Event/Events/Application/FinishedTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Finished::class)] +#[Small] +final class FinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $shellExitCode = 0; + + $event = new Finished($telemetryInfo, $shellExitCode); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($shellExitCode, $event->shellExitCode()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Finished($this->telemetryInfo(), 0); + + $this->assertSame('PHPUnit Finished (Shell Exit Code: 0)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Application/StartedTest.php b/tests/unit/Event/Events/Application/StartedTest.php new file mode 100644 index 00000000000..3d7f6d18efe --- /dev/null +++ b/tests/unit/Event/Events/Application/StartedTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Application; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Runtime\Runtime; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Started::class)] +#[Small] +final class StartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $runtime = new Runtime; + + $event = new Started( + $telemetryInfo, + $runtime, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($runtime, $event->runtime()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Started( + $this->telemetryInfo(), + new Runtime, + ); + + $this->assertStringMatchesFormat('PHPUnit Started (PHPUnit %s using PHP %s)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/AdditionalInformationProvidedTest.php b/tests/unit/Event/Events/Test/AdditionalInformationProvidedTest.php new file mode 100644 index 00000000000..80210406681 --- /dev/null +++ b/tests/unit/Event/Events/Test/AdditionalInformationProvidedTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AdditionalInformationProvided::class)] +#[Small] +final class AdditionalInformationProvidedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $additionalInformation = 'additional information'; + + $event = new AdditionalInformationProvided( + $telemetryInfo, + $test, + $additionalInformation, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($additionalInformation, $event->additionalInformation()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AdditionalInformationProvided( + $this->telemetryInfo(), + $this->testValueObject(), + 'additional information', + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Provided Additional Information +additional information +EOT + , + $event->asString(), + ); + } +} diff --git a/tests/unit/Event/Events/Test/ComparatorRegisteredTest.php b/tests/unit/Event/Events/Test/ComparatorRegisteredTest.php new file mode 100644 index 00000000000..1d505790d82 --- /dev/null +++ b/tests/unit/Event/Events/Test/ComparatorRegisteredTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ComparatorRegistered::class)] +#[Small] +final class ComparatorRegisteredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $className = 'ClassName'; + + $event = new ComparatorRegistered( + $telemetryInfo, + $className, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($className, $event->className()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ComparatorRegistered( + $this->telemetryInfo(), + 'ClassName', + ); + + $this->assertSame('Comparator Registered (ClassName)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/CustomTestMethodInvocationUsedTest.php b/tests/unit/Event/Events/Test/CustomTestMethodInvocationUsedTest.php new file mode 100644 index 00000000000..4f49eb9b804 --- /dev/null +++ b/tests/unit/Event/Events/Test/CustomTestMethodInvocationUsedTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(CustomTestMethodInvocationUsed::class)] +#[Small] +final class CustomTestMethodInvocationUsedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $customTestMethodInvocation = $this->calledMethod(); + + $event = new CustomTestMethodInvocationUsed( + $telemetryInfo, + $test, + $customTestMethodInvocation, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($customTestMethodInvocation, $event->customTestMethodInvocation()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new CustomTestMethodInvocationUsed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + 'Custom Test Method Invocation Used (ExampleTest::invokeTestMethod)', + $event->asString(), + ); + } + + private function calledMethod(): ClassMethod + { + return new ClassMethod('ExampleTest', 'invokeTestMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledTest.php new file mode 100644 index 00000000000..1278a101f09 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterLastTestMethodCalled::class)] +#[Small] +final class AfterLastTestMethodCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + + $event = new AfterLastTestMethodCalled( + $telemetryInfo, + $testClassName, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterLastTestMethodCalled( + $this->telemetryInfo(), + 'test class name', + $this->calledMethod(), + ); + + $this->assertSame('After Last Test Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredTest.php new file mode 100644 index 00000000000..f79c58599d6 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterLastTestMethodErrored::class)] +#[Small] +final class AfterLastTestMethodErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new AfterLastTestMethodErrored( + $telemetryInfo, + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterLastTestMethodErrored( + $this->telemetryInfo(), + 'test class name', + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Last Test Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedTest.php new file mode 100644 index 00000000000..2ce12a3410b --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterLastTestMethodFailed::class)] +#[Small] +final class AfterLastTestMethodFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new AfterLastTestMethodFailed( + $telemetryInfo, + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterLastTestMethodFailed( + $this->telemetryInfo(), + 'test class name', + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Last Test Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedTest.php new file mode 100644 index 00000000000..472d1c33bb6 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterLastTestMethodFinishedTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterLastTestMethodFinished::class)] +#[Small] +final class AfterLastTestMethodFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethods = $this->calledMethods(); + + $event = new AfterLastTestMethodFinished( + $telemetryInfo, + $testClassName, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterLastTestMethodFinished( + $this->telemetryInfo(), + self::class, + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Last Test Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT + , + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodCalledTest.php new file mode 100644 index 00000000000..49b7af516eb --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterTestMethodCalled::class)] +#[Small] +final class AfterTestMethodCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + + $event = new AfterTestMethodCalled( + $telemetryInfo, + $test, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterTestMethodCalled( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + ); + + $this->assertSame('After Test Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodErroredTest.php new file mode 100644 index 00000000000..dbae42f4f94 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterTestMethodErrored::class)] +#[Small] +final class AfterTestMethodErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new AfterTestMethodErrored( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterTestMethodErrored( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Test Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFailedTest.php new file mode 100644 index 00000000000..dd70b70bdb0 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterTestMethodFailed::class)] +#[Small] +final class AfterTestMethodFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new AfterTestMethodFailed( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterTestMethodFailed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Test Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFinishedTest.php new file mode 100644 index 00000000000..cc2d82add8f --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/AfterTestMethodFinishedTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(AfterTestMethodFinished::class)] +#[Small] +final class AfterTestMethodFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethods = $this->calledMethods(); + + $event = new AfterTestMethodFinished( + $telemetryInfo, + $test, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new AfterTestMethodFinished( + $this->telemetryInfo(), + $this->testValueObject(), + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +After Test Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT, + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledTest.php new file mode 100644 index 00000000000..55445240a51 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeFirstTestMethodCalled::class)] +#[Small] +final class BeforeFirstTestMethodCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + + $event = new BeforeFirstTestMethodCalled( + $telemetryInfo, + $testClassName, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeFirstTestMethodCalled( + $this->telemetryInfo(), + 'Test', + $this->calledMethod(), + ); + + $this->assertSame('Before First Test Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredTest.php new file mode 100644 index 00000000000..fdba3ff4b1b --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeFirstTestMethodErrored::class)] +#[Small] +final class BeforeFirstTestMethodErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new BeforeFirstTestMethodErrored( + $telemetryInfo, + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeFirstTestMethodErrored( + $this->telemetryInfo(), + 'Test', + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before First Test Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedTest.php new file mode 100644 index 00000000000..a08bb3f3b42 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeFirstTestMethodFailed::class)] +#[Small] +final class BeforeFirstTestMethodFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new BeforeFirstTestMethodFailed( + $telemetryInfo, + $testClassName, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeFirstTestMethodFailed( + $this->telemetryInfo(), + 'Test', + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before First Test Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedTest.php new file mode 100644 index 00000000000..c88dd24d5c7 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeFirstTestMethodFinishedTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeFirstTestMethodFinished::class)] +#[Small] +final class BeforeFirstTestMethodFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testClassName = 'Test'; + $calledMethods = $this->calledMethods(); + + $event = new BeforeFirstTestMethodFinished( + $telemetryInfo, + $testClassName, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testClassName, $event->testClassName()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeFirstTestMethodFinished( + $this->telemetryInfo(), + 'Test', + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before First Test Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT, + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodCalledTest.php new file mode 100644 index 00000000000..878cef8df74 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeTestMethodCalled::class)] +#[Small] +final class BeforeTestMethodCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + + $event = new BeforeTestMethodCalled( + $telemetryInfo, + $test, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeTestMethodCalled( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + ); + + $this->assertSame('Before Test Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodErroredTest.php new file mode 100644 index 00000000000..e8edf684984 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeTestMethodErrored::class)] +#[Small] +final class BeforeTestMethodErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new BeforeTestMethodErrored( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeTestMethodErrored( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before Test Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFailedTest.php new file mode 100644 index 00000000000..cbd3e21497b --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeTestMethodFailed::class)] +#[Small] +final class BeforeTestMethodFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new BeforeTestMethodFailed( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeTestMethodFailed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before Test Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedTest.php new file mode 100644 index 00000000000..cbbac3f0365 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/BeforeTestMethodFinishedTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BeforeTestMethodFinished::class)] +#[Small] +final class BeforeTestMethodFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethods = $this->calledMethods(); + + $event = new BeforeTestMethodFinished( + $telemetryInfo, + $test, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BeforeTestMethodFinished( + $this->telemetryInfo(), + $this->testValueObject(), + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Before Test Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT, + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PostConditionCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/PostConditionCalledTest.php new file mode 100644 index 00000000000..2117922a850 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PostConditionCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PostConditionCalled::class)] +#[Small] +final class PostConditionCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + + $event = new PostConditionCalled( + $telemetryInfo, + $test, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PostConditionCalled( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + ); + + $this->assertSame('Post Condition Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PostConditionErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/PostConditionErroredTest.php new file mode 100644 index 00000000000..440f3c1191f --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PostConditionErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PostConditionErrored::class)] +#[Small] +final class PostConditionErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new PostConditionErrored( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PostConditionErrored( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Post Condition Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PostConditionFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/PostConditionFailedTest.php new file mode 100644 index 00000000000..9b9c776a068 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PostConditionFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PostConditionFailed::class)] +#[Small] +final class PostConditionFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new PostConditionFailed( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PostConditionFailed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Post Condition Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PostConditionFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/PostConditionFinishedTest.php new file mode 100644 index 00000000000..047f627b3dd --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PostConditionFinishedTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PostConditionFinished::class)] +#[Small] +final class PostConditionFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethods = $this->calledMethods(); + + $event = new PostConditionFinished( + $telemetryInfo, + $test, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PostConditionFinished( + $this->telemetryInfo(), + $this->testValueObject(), + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Post Condition Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT, + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PreConditionCalledTest.php b/tests/unit/Event/Events/Test/HookMethod/PreConditionCalledTest.php new file mode 100644 index 00000000000..a738492ec1f --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PreConditionCalledTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreConditionCalled::class)] +#[Small] +final class PreConditionCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + + $event = new PreConditionCalled( + $telemetryInfo, + $test, + $calledMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreConditionCalled( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + ); + + $this->assertSame('Pre Condition Method Called (HookClass::hookMethod)', $event->asString()); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PreConditionErroredTest.php b/tests/unit/Event/Events/Test/HookMethod/PreConditionErroredTest.php new file mode 100644 index 00000000000..064737f863e --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PreConditionErroredTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreConditionErrored::class)] +#[Small] +final class PreConditionErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new PreConditionErrored( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreConditionErrored( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Pre Condition Method Errored (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PreConditionFailedTest.php b/tests/unit/Event/Events/Test/HookMethod/PreConditionFailedTest.php new file mode 100644 index 00000000000..2d8e4c54ee3 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PreConditionFailedTest.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreConditionFailed::class)] +#[Small] +final class PreConditionFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethod = $this->calledMethod(); + $throwable = Code\ThrowableBuilder::from(new Exception('message')); + + $event = new PreConditionFailed( + $telemetryInfo, + $test, + $calledMethod, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethod, $event->calledMethod()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreConditionFailed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->calledMethod(), + Code\ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Pre Condition Method Failed (HookClass::hookMethod) +message +EOT, + $event->asString(), + ); + } + + private function calledMethod(): Code\ClassMethod + { + return new Code\ClassMethod('HookClass', 'hookMethod'); + } +} diff --git a/tests/unit/Event/Events/Test/HookMethod/PreConditionFinishedTest.php b/tests/unit/Event/Events/Test/HookMethod/PreConditionFinishedTest.php new file mode 100644 index 00000000000..0bca77d9e30 --- /dev/null +++ b/tests/unit/Event/Events/Test/HookMethod/PreConditionFinishedTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreConditionFinished::class)] +#[Small] +final class PreConditionFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $calledMethods = $this->calledMethods(); + + $event = new PreConditionFinished( + $telemetryInfo, + $test, + ...$calledMethods, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($calledMethods, $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreConditionFinished( + $this->telemetryInfo(), + $this->testValueObject(), + ...$this->calledMethods(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Pre Condition Method Finished: +- HookClass::hookMethod +- AnotherHookClass::anotherHookMethod +EOT, + $event->asString(), + ); + } + + /** + * @return list + */ + private function calledMethods(): array + { + return [ + new Code\ClassMethod('HookClass', 'hookMethod'), + new Code\ClassMethod('AnotherHookClass', 'anotherHookMethod'), + ]; + } +} diff --git a/tests/unit/Event/Events/Test/Issue/ConsideredRiskyTest.php b/tests/unit/Event/Events/Test/Issue/ConsideredRiskyTest.php new file mode 100644 index 00000000000..3b7c61f9588 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/ConsideredRiskyTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ConsideredRisky::class)] +#[Small] +final class ConsideredRiskyTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + + $message = 'message'; + + $event = new ConsideredRisky( + $telemetryInfo, + $test, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ConsideredRisky( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Considered Risky (FooTest::testBar) +message +EOT, + $event->asString(), + ); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/DeprecationTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/DeprecationTriggeredTest.php new file mode 100644 index 00000000000..c796b622817 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/DeprecationTriggeredTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(DeprecationTriggered::class)] +#[Small] +final class DeprecationTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + $ignoredByTest = false; + $trigger = IssueTrigger::unknown(); + $stackTrace = 'stack trace'; + + $event = new DeprecationTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + $stackTrace, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame($ignoredByTest, $event->ignoredByTest()); + $this->assertSame('Test Triggered Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code) in file:1' . PHP_EOL . 'message', $event->asString()); + $this->assertSame($trigger, $event->trigger()); + $this->assertSame($stackTrace, $event->stackTrace()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new DeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + false, + IssueTrigger::unknown(), + 'stack trace', + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByTest(): void + { + $event = new DeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + false, + true, + IssueTrigger::unknown(), + 'stack trace', + ); + + $this->assertTrue($event->ignoredByTest()); + $this->assertSame('Test Triggered Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, ignored by test) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new DeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + false, + IssueTrigger::unknown(), + 'stack trace', + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/ErrorTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/ErrorTriggeredTest.php new file mode 100644 index 00000000000..63c5f3eebea --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/ErrorTriggeredTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ErrorTriggered::class)] +#[Small] +final class ErrorTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + + $event = new ErrorTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame('Test Triggered Error (FooTest::testBar) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new ErrorTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered Error (FooTest::testBar, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/NoticeTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/NoticeTriggeredTest.php new file mode 100644 index 00000000000..7bab2867d13 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/NoticeTriggeredTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(NoticeTriggered::class)] +#[Small] +final class NoticeTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $event = new NoticeTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame('Test Triggered Notice (FooTest::testBar) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new NoticeTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered Notice (FooTest::testBar, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new NoticeTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered Notice (FooTest::testBar, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpDeprecationTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpDeprecationTriggeredTest.php new file mode 100644 index 00000000000..b7653146091 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpDeprecationTriggeredTest.php @@ -0,0 +1,111 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\IssueTrigger\IssueTrigger; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpDeprecationTriggered::class)] +#[Small] +final class PhpDeprecationTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + $ignoredByTest = false; + $trigger = IssueTrigger::unknown(); + + $event = new PhpDeprecationTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + $ignoredByTest, + $trigger, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame($ignoredByTest, $event->ignoredByTest()); + $this->assertSame('Test Triggered PHP Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code) in file:1' . PHP_EOL . 'message', $event->asString()); + $this->assertSame($trigger, $event->trigger()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new PhpDeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + false, + IssueTrigger::unknown(), + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered PHP Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByTest(): void + { + $event = new PhpDeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + false, + true, + IssueTrigger::unknown(), + ); + + $this->assertTrue($event->ignoredByTest()); + $this->assertSame('Test Triggered PHP Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, ignored by test) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new PhpDeprecationTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + false, + IssueTrigger::unknown(), + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered PHP Deprecation (FooTest::testBar, unknown if issue was triggered in first-party code or third-party code, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpNoticeTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpNoticeTriggeredTest.php new file mode 100644 index 00000000000..8140ff3184f --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpNoticeTriggeredTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpNoticeTriggered::class)] +#[Small] +final class PhpNoticeTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $event = new PhpNoticeTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame('Test Triggered PHP Notice (FooTest::testBar) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new PhpNoticeTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered PHP Notice (FooTest::testBar, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new PhpNoticeTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered PHP Notice (FooTest::testBar, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpWarningTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpWarningTriggeredTest.php new file mode 100644 index 00000000000..a6fed8356f4 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpWarningTriggeredTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpWarningTriggered::class)] +#[Small] +final class PhpWarningTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $event = new PhpWarningTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame('Test Triggered PHP Warning (FooTest::testBar) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new PhpWarningTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered PHP Warning (FooTest::testBar, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new PhpWarningTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered PHP Warning (FooTest::testBar, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredTest.php new file mode 100644 index 00000000000..e3930bd612d --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpunitDeprecationTriggeredTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpunitDeprecationTriggered::class)] +#[Small] +final class PhpunitDeprecationTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + + $event = new PhpunitDeprecationTriggered( + $telemetryInfo, + $test, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame('Test Triggered PHPUnit Deprecation (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpunitErrorTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpunitErrorTriggeredTest.php new file mode 100644 index 00000000000..36faa267647 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpunitErrorTriggeredTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpunitErrorTriggered::class)] +#[Small] +final class PhpunitErrorTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + + $event = new PhpunitErrorTriggered( + $telemetryInfo, + $test, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame('Test Triggered PHPUnit Error (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpunitNoticeTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpunitNoticeTriggeredTest.php new file mode 100644 index 00000000000..bb734e46158 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpunitNoticeTriggeredTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpunitNoticeTriggered::class)] +#[Small] +final class PhpunitNoticeTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + + $event = new PhpunitNoticeTriggered( + $telemetryInfo, + $test, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame('Test Triggered PHPUnit Notice (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/PhpunitWarningTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/PhpunitWarningTriggeredTest.php new file mode 100644 index 00000000000..f6ba1ee24d1 --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/PhpunitWarningTriggeredTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PhpunitWarningTriggered::class)] +#[Small] +final class PhpunitWarningTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $ignoredByTest = false; + + $event = new PhpunitWarningTriggered( + $telemetryInfo, + $test, + $message, + $ignoredByTest, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($ignoredByTest, $event->ignoredByTest()); + $this->assertSame('Test Triggered PHPUnit Warning (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByTest(): void + { + $event = new PhpunitWarningTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + true, + ); + + $this->assertTrue($event->ignoredByTest()); + $this->assertSame('Test Triggered PHPUnit Warning (FooTest::testBar, ignored by test)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Issue/WarningTriggeredTest.php b/tests/unit/Event/Events/Test/Issue/WarningTriggeredTest.php new file mode 100644 index 00000000000..394af14b2cc --- /dev/null +++ b/tests/unit/Event/Events/Test/Issue/WarningTriggeredTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(WarningTriggered::class)] +#[Small] +final class WarningTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'message'; + $file = 'file'; + $line = 1; + $suppressed = false; + $ignoredByBaseline = false; + + $event = new WarningTriggered( + $telemetryInfo, + $test, + $message, + $file, + $line, + $suppressed, + $ignoredByBaseline, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + $this->assertSame($file, $event->file()); + $this->assertSame($line, $event->line()); + $this->assertSame($suppressed, $event->wasSuppressed()); + $this->assertSame($ignoredByBaseline, $event->ignoredByBaseline()); + $this->assertSame('Test Triggered Warning (FooTest::testBar) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeIgnoredByBaseline(): void + { + $event = new WarningTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + false, + true, + ); + + $this->assertTrue($event->ignoredByBaseline()); + $this->assertSame('Test Triggered Warning (FooTest::testBar, ignored by baseline) in file:1' . PHP_EOL . 'message', $event->asString()); + } + + public function testCanBeSuppressed(): void + { + $event = new WarningTriggered( + $this->telemetryInfo(), + $this->testValueObject(), + 'message', + 'file', + 1, + true, + false, + ); + + $this->assertTrue($event->wasSuppressed()); + $this->assertSame('Test Triggered Warning (FooTest::testBar, suppressed using operator) in file:1' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodCalledTest.php b/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodCalledTest.php new file mode 100644 index 00000000000..d8f8acc97a5 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodCalledTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(DataProviderMethodCalled::class)] +#[Small] +final class DataProviderMethodCalledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testMethod = new ClassMethod('ClassTest', 'testOne'); + $dataProviderMethod = new ClassMethod('ClassTest', 'dataProvider'); + + $event = new DataProviderMethodCalled( + $telemetryInfo, + $testMethod, + $dataProviderMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testMethod, $event->testMethod()); + $this->assertSame($dataProviderMethod, $event->dataProviderMethod()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new DataProviderMethodCalled( + $this->telemetryInfo(), + new ClassMethod('ClassTest', 'testOne'), + new ClassMethod('ClassTest', 'dataProvider'), + ); + + $this->assertSame('Data Provider Method Called (ClassTest::dataProvider for test method ClassTest::testOne)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedTest.php b/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedTest.php new file mode 100644 index 00000000000..068207671d9 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/DataProviderMethodFinishedTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\ClassMethod; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(DataProviderMethodFinished::class)] +#[Small] +final class DataProviderMethodFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testMethod = new ClassMethod('ClassTest', 'testOne'); + $dataProviderMethod = new ClassMethod('ClassTest', 'dataProvider'); + + $event = new DataProviderMethodFinished( + $telemetryInfo, + $testMethod, + $dataProviderMethod, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testMethod, $event->testMethod()); + $this->assertSame([$dataProviderMethod], $event->calledMethods()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new DataProviderMethodFinished( + $this->telemetryInfo(), + new ClassMethod('ClassTest', 'testOne'), + new ClassMethod('ClassTest', 'dataProvider'), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Data Provider Method Finished for ClassTest::testOne: +- ClassTest::dataProvider +EOT + , + $event->asString(), + ); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/FinishedTest.php b/tests/unit/Event/Events/Test/Lifecycle/FinishedTest.php new file mode 100644 index 00000000000..510d1e933bc --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/FinishedTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Finished::class)] +#[Small] +final class FinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + + $event = new Finished( + $telemetryInfo, + $test, + 1, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame(1, $event->numberOfAssertionsPerformed()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Finished( + $this->telemetryInfo(), + $this->testValueObject(), + 1, + ); + + $this->assertSame('Test Finished (FooTest::testBar)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/PreparationErroredTest.php b/tests/unit/Event/Events/Test/Lifecycle/PreparationErroredTest.php new file mode 100644 index 00000000000..9ae9d1154c4 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/PreparationErroredTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreparationErrored::class)] +#[Small] +final class PreparationErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $event = new PreparationErrored( + $telemetryInfo, + $test, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreparationErrored( + $this->telemetryInfo(), + $this->testValueObject(), + ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertSame('Test Preparation Errored (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/PreparationFailedTest.php b/tests/unit/Event/Events/Test/Lifecycle/PreparationFailedTest.php new file mode 100644 index 00000000000..c85ef9f3799 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/PreparationFailedTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use const PHP_EOL; +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreparationFailed::class)] +#[Small] +final class PreparationFailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = ThrowableBuilder::from(new Exception('message')); + + $event = new PreparationFailed( + $telemetryInfo, + $test, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreparationFailed( + $this->telemetryInfo(), + $this->testValueObject(), + ThrowableBuilder::from(new Exception('message')), + ); + + $this->assertSame('Test Preparation Failed (FooTest::testBar)' . PHP_EOL . 'message', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/PreparationStartedTest.php b/tests/unit/Event/Events/Test/Lifecycle/PreparationStartedTest.php new file mode 100644 index 00000000000..3c7a4223091 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/PreparationStartedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PreparationStarted::class)] +#[Small] +final class PreparationStartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + + $event = new PreparationStarted( + $telemetryInfo, + $test, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PreparationStarted( + $this->telemetryInfo(), + $this->testValueObject(), + ); + + $this->assertSame('Test Preparation Started (FooTest::testBar)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Lifecycle/PreparedTest.php b/tests/unit/Event/Events/Test/Lifecycle/PreparedTest.php new file mode 100644 index 00000000000..05dc12c8c05 --- /dev/null +++ b/tests/unit/Event/Events/Test/Lifecycle/PreparedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Prepared::class)] +#[Small] +final class PreparedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + + $event = new Prepared( + $telemetryInfo, + $test, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Prepared( + $this->telemetryInfo(), + $this->testValueObject(), + ); + + $this->assertSame('Test Prepared (FooTest::testBar)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Outcome/ErroredTest.php b/tests/unit/Event/Events/Test/Outcome/ErroredTest.php new file mode 100644 index 00000000000..a352030810f --- /dev/null +++ b/tests/unit/Event/Events/Test/Outcome/ErroredTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Errored::class)] +#[Small] +final class ErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = $this->throwable(); + + $event = new Errored( + $telemetryInfo, + $test, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Errored( + $this->telemetryInfo(), + $this->testValueObject(), + $this->throwable(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Errored (FooTest::testBar) +error +EOT, + $event->asString(), + ); + } + + private function throwable(): Code\Throwable + { + return Code\ThrowableBuilder::from(new Exception('error')); + } +} diff --git a/tests/unit/Event/Events/Test/Outcome/FailedTest.php b/tests/unit/Event/Events/Test/Outcome/FailedTest.php new file mode 100644 index 00000000000..d9a030c67ef --- /dev/null +++ b/tests/unit/Event/Events/Test/Outcome/FailedTest.php @@ -0,0 +1,91 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Event\Code\ComparisonFailure; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Failed::class)] +#[Small] +final class FailedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = $this->throwable(); + $comparisonFailure = $this->comparisonFailure(); + + $event = new Failed( + $telemetryInfo, + $test, + $throwable, + $comparisonFailure, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + $this->assertSame($comparisonFailure, $event->comparisonFailure()); + $this->assertTrue($event->hasComparisonFailure()); + } + + public function testThrowsExceptionOnAccessToUnspecifiedComparisonFailure(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = $this->throwable(); + + $event = new Failed( + $telemetryInfo, + $test, + $throwable, + null, + ); + + $this->assertFalse($event->hasComparisonFailure()); + + $this->expectException(NoComparisonFailureException::class); + + $event->comparisonFailure(); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Failed( + $this->telemetryInfo(), + $this->testValueObject(), + $this->throwable(), + null, + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Failed (FooTest::testBar) +failure +EOT, + $event->asString(), + ); + } + + private function throwable(): Code\Throwable + { + return Code\ThrowableBuilder::from(new Exception('failure')); + } + + private function comparisonFailure(): ComparisonFailure + { + return new ComparisonFailure('expected', 'actual', 'diff'); + } +} diff --git a/tests/unit/Event/Events/Test/Outcome/MarkedIncompleteTest.php b/tests/unit/Event/Events/Test/Outcome/MarkedIncompleteTest.php new file mode 100644 index 00000000000..dac2fd79fb7 --- /dev/null +++ b/tests/unit/Event/Events/Test/Outcome/MarkedIncompleteTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use Exception; +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Event\Code; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(MarkedIncomplete::class)] +#[Small] +final class MarkedIncompleteTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $throwable = $this->throwable(); + + $event = new MarkedIncomplete( + $telemetryInfo, + $test, + $throwable, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($throwable, $event->throwable()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new MarkedIncomplete( + $this->telemetryInfo(), + $this->testValueObject(), + $this->throwable(), + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Marked Incomplete (FooTest::testBar) +incomplete +EOT, + $event->asString(), + ); + } + + private function throwable(): Code\Throwable + { + return Code\ThrowableBuilder::from(new Exception('incomplete')); + } +} diff --git a/tests/unit/Event/Events/Test/Outcome/PassedTest.php b/tests/unit/Event/Events/Test/Outcome/PassedTest.php new file mode 100644 index 00000000000..c8276522e79 --- /dev/null +++ b/tests/unit/Event/Events/Test/Outcome/PassedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Passed::class)] +#[Small] +final class PassedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + + $event = new Passed( + $telemetryInfo, + $test, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Passed( + $this->telemetryInfo(), + $this->testValueObject(), + ); + + $this->assertSame('Test Passed (FooTest::testBar)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/Test/Outcome/SkippedTest.php b/tests/unit/Event/Events/Test/Outcome/SkippedTest.php new file mode 100644 index 00000000000..48f09e03ae8 --- /dev/null +++ b/tests/unit/Event/Events/Test/Outcome/SkippedTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Skipped::class)] +#[Small] +final class SkippedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $test = $this->testValueObject(); + $message = 'skipped'; + + $event = new Skipped( + $telemetryInfo, + $test, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($test, $event->test()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Skipped( + $this->telemetryInfo(), + $this->testValueObject(), + 'skipped', + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Skipped (FooTest::testBar) +skipped +EOT, + $event->asString(), + ); + } +} diff --git a/tests/unit/Event/Events/Test/PrintedUnexpectedOutputTest.php b/tests/unit/Event/Events/Test/PrintedUnexpectedOutputTest.php new file mode 100644 index 00000000000..4959cb418ef --- /dev/null +++ b/tests/unit/Event/Events/Test/PrintedUnexpectedOutputTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PrintedUnexpectedOutput::class)] +#[Small] +final class PrintedUnexpectedOutputTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $output = 'output'; + + $event = new PrintedUnexpectedOutput( + $telemetryInfo, + $output, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($output, $event->output()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PrintedUnexpectedOutput( + $this->telemetryInfo(), + 'output', + ); + + $this->assertStringEqualsStringIgnoringLineEndings( + <<<'EOT' +Test Printed Unexpected Output +output +EOT + , + $event->asString(), + ); + } +} diff --git a/tests/unit/Event/Events/TestDouble/MockObjectCreatedTest.php b/tests/unit/Event/Events/TestDouble/MockObjectCreatedTest.php new file mode 100644 index 00000000000..f91b9916c79 --- /dev/null +++ b/tests/unit/Event/Events/TestDouble/MockObjectCreatedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(MockObjectCreated::class)] +#[Small] +final class MockObjectCreatedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $className = 'OriginalType'; + + $event = new MockObjectCreated( + $telemetryInfo, + $className, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($className, $event->className()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new MockObjectCreated( + $this->telemetryInfo(), + 'OriginalType', + ); + + $this->assertSame('Mock Object Created (OriginalType)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestDouble/MockObjectForIntersectionOfInterfacesCreatedTest.php b/tests/unit/Event/Events/TestDouble/MockObjectForIntersectionOfInterfacesCreatedTest.php new file mode 100644 index 00000000000..63e662542bc --- /dev/null +++ b/tests/unit/Event/Events/TestDouble/MockObjectForIntersectionOfInterfacesCreatedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(MockObjectForIntersectionOfInterfacesCreated::class)] +#[Small] +final class MockObjectForIntersectionOfInterfacesCreatedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $interfaces = ['AnInterface', 'AnotherInterface']; + + $event = new MockObjectForIntersectionOfInterfacesCreated( + $telemetryInfo, + $interfaces, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($interfaces, $event->interfaces()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new MockObjectForIntersectionOfInterfacesCreated( + $this->telemetryInfo(), + ['AnInterface', 'AnotherInterface'], + ); + + $this->assertSame('Mock Object Created (AnInterface&AnotherInterface)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestDouble/PartialMockObjectCreatedTest.php b/tests/unit/Event/Events/TestDouble/PartialMockObjectCreatedTest.php new file mode 100644 index 00000000000..6d612c4574a --- /dev/null +++ b/tests/unit/Event/Events/TestDouble/PartialMockObjectCreatedTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(PartialMockObjectCreated::class)] +#[Small] +final class PartialMockObjectCreatedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $className = 'OriginalType'; + $methodNames = [ + 'foo', + 'bar', + 'baz', + ]; + + $event = new PartialMockObjectCreated( + $telemetryInfo, + $className, + ...$methodNames, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($className, $event->className()); + $this->assertSame($methodNames, $event->methodNames()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new PartialMockObjectCreated( + $this->telemetryInfo(), + 'OriginalType', + ); + + $this->assertSame('Partial Mock Object Created (OriginalType)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestDouble/TestStubCreatedTest.php b/tests/unit/Event/Events/TestDouble/TestStubCreatedTest.php new file mode 100644 index 00000000000..0b4fb3bfe96 --- /dev/null +++ b/tests/unit/Event/Events/TestDouble/TestStubCreatedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(TestStubCreated::class)] +#[Small] +final class TestStubCreatedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $className = 'OriginalType'; + + $event = new TestStubCreated( + $telemetryInfo, + $className, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($className, $event->className()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new TestStubCreated( + $this->telemetryInfo(), + 'OriginalType', + ); + + $this->assertSame('Test Stub Created (OriginalType)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestDouble/TestStubForIntersectionOfInterfacesCreatedTest.php b/tests/unit/Event/Events/TestDouble/TestStubForIntersectionOfInterfacesCreatedTest.php new file mode 100644 index 00000000000..c8495b85a9b --- /dev/null +++ b/tests/unit/Event/Events/TestDouble/TestStubForIntersectionOfInterfacesCreatedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Test; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(TestStubForIntersectionOfInterfacesCreated::class)] +#[Small] +final class TestStubForIntersectionOfInterfacesCreatedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $interfaces = ['AnInterface', 'AnotherInterface']; + + $event = new TestStubForIntersectionOfInterfacesCreated( + $telemetryInfo, + $interfaces, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($interfaces, $event->interfaces()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new TestStubForIntersectionOfInterfacesCreated( + $this->telemetryInfo(), + ['AnInterface', 'AnotherInterface'], + ); + + $this->assertSame('Test Stub Created (AnInterface&AnotherInterface)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/BootstrapFinishedTest.php b/tests/unit/Event/Events/TestRunner/BootstrapFinishedTest.php new file mode 100644 index 00000000000..cb7cb6fafaf --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/BootstrapFinishedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(BootstrapFinished::class)] +#[Small] +final class BootstrapFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $filename = 'bootstrap.php'; + + $event = new BootstrapFinished( + $telemetryInfo, + $filename, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($filename, $event->filename()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new BootstrapFinished( + $this->telemetryInfo(), + 'bootstrap.php', + ); + + $this->assertSame('Bootstrap Finished (bootstrap.php)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ChildProcessErroredTest.php b/tests/unit/Event/Events/TestRunner/ChildProcessErroredTest.php new file mode 100644 index 00000000000..2625f9ca512 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ChildProcessErroredTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ChildProcessErrored::class)] +#[Small] +final class ChildProcessErroredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ChildProcessErrored( + $telemetryInfo, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ChildProcessErrored( + $this->telemetryInfo(), + ); + + $this->assertSame('Child Process Errored', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ChildProcessFinishedTest.php b/tests/unit/Event/Events/TestRunner/ChildProcessFinishedTest.php new file mode 100644 index 00000000000..79bfaab0ca8 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ChildProcessFinishedTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ChildProcessFinished::class)] +#[Small] +final class ChildProcessFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $stdout = 'output'; + $stderr = 'error'; + + $event = new ChildProcessFinished( + $telemetryInfo, + $stdout, + $stderr, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($stdout, $event->stdout()); + $this->assertSame($stderr, $event->stderr()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ChildProcessFinished( + $this->telemetryInfo(), + 'output', + 'error', + ); + + $this->assertSame('Child Process Finished', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ChildProcessStartedTest.php b/tests/unit/Event/Events/TestRunner/ChildProcessStartedTest.php new file mode 100644 index 00000000000..80a4864bd90 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ChildProcessStartedTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ChildProcessStarted::class)] +#[Small] +final class ChildProcessStartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ChildProcessStarted( + $telemetryInfo, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ChildProcessStarted( + $this->telemetryInfo(), + ); + + $this->assertSame('Child Process Started', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ConfiguredTest.php b/tests/unit/Event/Events/TestRunner/ConfiguredTest.php new file mode 100644 index 00000000000..7f169d05f05 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ConfiguredTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\TextUI\CliArguments\Builder; +use PHPUnit\TextUI\Configuration\Configuration; +use PHPUnit\TextUI\Configuration\Merger; +use PHPUnit\TextUI\XmlConfiguration\DefaultConfiguration; + +#[CoversClass(Configured::class)] +#[Small] +final class ConfiguredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $configuration = $this->configuration(); + + $event = new Configured( + $telemetryInfo, + $configuration, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($configuration, $event->configuration()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Configured( + $this->telemetryInfo(), + $this->configuration(), + ); + + $this->assertSame('Test Runner Configured', $event->asString()); + } + + private function configuration(): Configuration + { + return (new Merger)->merge( + (new Builder)->fromParameters([]), + DefaultConfiguration::create(), + ); + } +} diff --git a/tests/unit/Event/Events/TestRunner/DeprecationTriggeredTest.php b/tests/unit/Event/Events/TestRunner/DeprecationTriggeredTest.php new file mode 100644 index 00000000000..ac1bc41718a --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/DeprecationTriggeredTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(DeprecationTriggered::class)] +#[Small] +final class DeprecationTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $message = 'message'; + + $event = new DeprecationTriggered( + $telemetryInfo, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new DeprecationTriggered( + $this->telemetryInfo(), + 'message', + ); + + $this->assertSame('Test Runner Triggered Deprecation (message)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/EventFacadeSealedTest.php b/tests/unit/Event/Events/TestRunner/EventFacadeSealedTest.php new file mode 100644 index 00000000000..a681ca58d64 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/EventFacadeSealedTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(EventFacadeSealed::class)] +#[Small] +final class EventFacadeSealedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new EventFacadeSealed($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new EventFacadeSealed($this->telemetryInfo()); + + $this->assertSame('Event Facade Sealed', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ExecutionAbortedTest.php b/tests/unit/Event/Events/TestRunner/ExecutionAbortedTest.php new file mode 100644 index 00000000000..869ae4ce3ed --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ExecutionAbortedTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ExecutionAborted::class)] +#[Small] +final class ExecutionAbortedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ExecutionAborted($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ExecutionAborted($telemetryInfo); + + $this->assertSame('Test Runner Execution Aborted', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ExecutionFinishedTest.php b/tests/unit/Event/Events/TestRunner/ExecutionFinishedTest.php new file mode 100644 index 00000000000..b090a17e786 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ExecutionFinishedTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ExecutionFinished::class)] +#[Small] +final class ExecutionFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ExecutionFinished($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new ExecutionFinished($telemetryInfo); + + $this->assertSame('Test Runner Execution Finished', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ExecutionStartedTest.php b/tests/unit/Event/Events/TestRunner/ExecutionStartedTest.php new file mode 100644 index 00000000000..28373aa9e49 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ExecutionStartedTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ExecutionStarted::class)] +#[Small] +final class ExecutionStartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new ExecutionStarted($telemetryInfo, $testSuite); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + } + + public function testCanBeRepresentedAsString(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new ExecutionStarted($telemetryInfo, $testSuite); + + $this->assertSame('Test Runner Execution Started (9001 tests)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ExtensionBootstrappedTest.php b/tests/unit/Event/Events/TestRunner/ExtensionBootstrappedTest.php new file mode 100644 index 00000000000..644f2f47d64 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ExtensionBootstrappedTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ExtensionBootstrapped::class)] +#[Small] +final class ExtensionBootstrappedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $className = 'the-className'; + $parameters = ['foo' => 'bar']; + + $event = new ExtensionBootstrapped( + $telemetryInfo, + $className, + $parameters, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($className, $event->className()); + $this->assertSame($parameters, $event->parameters()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ExtensionBootstrapped( + $this->telemetryInfo(), + 'the-className', + [], + ); + + $this->assertSame('Extension Bootstrapped (the-className)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/ExtensionLoadedFromPharTest.php b/tests/unit/Event/Events/TestRunner/ExtensionLoadedFromPharTest.php new file mode 100644 index 00000000000..d14c4bef4bc --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/ExtensionLoadedFromPharTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(ExtensionLoadedFromPhar::class)] +#[Small] +final class ExtensionLoadedFromPharTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $filename = 'extension.phar'; + $name = 'example-extension'; + $version = '1.2.3'; + + $event = new ExtensionLoadedFromPhar( + $telemetryInfo, + $filename, + $name, + $version, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($filename, $event->filename()); + $this->assertSame($name, $event->name()); + $this->assertSame($version, $event->version()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new ExtensionLoadedFromPhar( + $this->telemetryInfo(), + 'extension.phar', + 'example-extension', + '1.2.3', + ); + + $this->assertSame('Extension Loaded from PHAR (example-extension 1.2.3)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/FinishedTest.php b/tests/unit/Event/Events/TestRunner/FinishedTest.php new file mode 100644 index 00000000000..a2317a30cda --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/FinishedTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Finished::class)] +#[Small] +final class FinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new Finished($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Finished($this->telemetryInfo()); + + $this->assertSame('Test Runner Finished', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/GarbageCollectionDisabledTest.php b/tests/unit/Event/Events/TestRunner/GarbageCollectionDisabledTest.php new file mode 100644 index 00000000000..e1feadc044f --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/GarbageCollectionDisabledTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(GarbageCollectionDisabled::class)] +#[Small] +final class GarbageCollectionDisabledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new GarbageCollectionDisabled($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new GarbageCollectionDisabled($this->telemetryInfo()); + + $this->assertSame('Test Runner Disabled Garbage Collection', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/GarbageCollectionEnabledTest.php b/tests/unit/Event/Events/TestRunner/GarbageCollectionEnabledTest.php new file mode 100644 index 00000000000..f435b7abb17 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/GarbageCollectionEnabledTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(GarbageCollectionEnabled::class)] +#[Small] +final class GarbageCollectionEnabledTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new GarbageCollectionEnabled($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new GarbageCollectionEnabled($this->telemetryInfo()); + + $this->assertSame('Test Runner Enabled Garbage Collection', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/GarbageCollectionTriggeredTest.php b/tests/unit/Event/Events/TestRunner/GarbageCollectionTriggeredTest.php new file mode 100644 index 00000000000..9fe6b5277e2 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/GarbageCollectionTriggeredTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(GarbageCollectionTriggered::class)] +#[Small] +final class GarbageCollectionTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new GarbageCollectionTriggered($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new GarbageCollectionTriggered($this->telemetryInfo()); + + $this->assertSame('Test Runner Triggered Garbage Collection', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/NoticeTriggeredTest.php b/tests/unit/Event/Events/TestRunner/NoticeTriggeredTest.php new file mode 100644 index 00000000000..ebd065cbf1e --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/NoticeTriggeredTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(NoticeTriggered::class)] +#[Small] +final class NoticeTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $message = 'message'; + + $event = new NoticeTriggered( + $telemetryInfo, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new NoticeTriggered( + $this->telemetryInfo(), + 'message', + ); + + $this->assertSame('Test Runner Triggered Notice (message)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/StartedTest.php b/tests/unit/Event/Events/TestRunner/StartedTest.php new file mode 100644 index 00000000000..d4072f6e09e --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/StartedTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Started::class)] +#[Small] +final class StartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new Started($telemetryInfo); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Started($this->telemetryInfo()); + + $this->assertSame('Test Runner Started', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedTest.php b/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedTest.php new file mode 100644 index 00000000000..34d66209dbb --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageFinishedTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(StaticAnalysisForCodeCoverageFinished::class)] +#[Small] +final class StaticAnalysisForCodeCoverageFinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $cacheHits = 1; + $cacheMisses = 2; + + $event = new StaticAnalysisForCodeCoverageFinished( + $telemetryInfo, + $cacheHits, + $cacheMisses, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($cacheHits, $event->cacheHits()); + $this->assertSame($cacheMisses, $event->cacheMisses()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new StaticAnalysisForCodeCoverageFinished( + $this->telemetryInfo(), + 1, + 2, + ); + + $this->assertSame('Static Analysis for Code Coverage Finished (1 cache hits, 2 cache misses)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedTest.php b/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedTest.php new file mode 100644 index 00000000000..214675385f5 --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/StaticAnalysisForCodeCoverageStartedTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(StaticAnalysisForCodeCoverageStarted::class)] +#[Small] +final class StaticAnalysisForCodeCoverageStartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + + $event = new StaticAnalysisForCodeCoverageStarted( + $telemetryInfo, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new StaticAnalysisForCodeCoverageStarted( + $this->telemetryInfo(), + ); + + $this->assertSame('Static Analysis for Code Coverage Started', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestRunner/WarningTriggeredTest.php b/tests/unit/Event/Events/TestRunner/WarningTriggeredTest.php new file mode 100644 index 00000000000..b84fae978fa --- /dev/null +++ b/tests/unit/Event/Events/TestRunner/WarningTriggeredTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestRunner; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(WarningTriggered::class)] +#[Small] +final class WarningTriggeredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $message = 'message'; + + $event = new WarningTriggered( + $telemetryInfo, + $message, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new WarningTriggered( + $this->telemetryInfo(), + 'message', + ); + + $this->assertSame('Test Runner Triggered Warning (message)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/FilteredTest.php b/tests/unit/Event/Events/TestSuite/FilteredTest.php new file mode 100644 index 00000000000..02a9ab7c021 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/FilteredTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Filtered::class)] +#[Small] +final class FilteredTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new Filtered( + $telemetryInfo, + $testSuite, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Filtered( + $this->telemetryInfo(), + $this->testSuiteValueObject(), + ); + + $this->assertSame('Test Suite Filtered (9001 tests)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/FinishedTest.php b/tests/unit/Event/Events/TestSuite/FinishedTest.php new file mode 100644 index 00000000000..e0d9623b129 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/FinishedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Finished::class)] +#[Small] +final class FinishedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new Finished( + $telemetryInfo, + $testSuite, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Finished( + $this->telemetryInfo(), + $this->testSuiteValueObject(), + ); + + $this->assertSame('Test Suite Finished (foo, 9001 tests)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/LoadedTest.php b/tests/unit/Event/Events/TestSuite/LoadedTest.php new file mode 100644 index 00000000000..dc899d40860 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/LoadedTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Loaded::class)] +#[Small] +final class LoadedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new Loaded($telemetryInfo, $testSuite); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Loaded( + $this->telemetryInfo(), + $this->testSuiteValueObject(), + ); + + $this->assertSame('Test Suite Loaded (9001 tests)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/SkippedTest.php b/tests/unit/Event/Events/TestSuite/SkippedTest.php new file mode 100644 index 00000000000..84e198779c0 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/SkippedTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Skipped::class)] +#[Small] +final class SkippedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + $message = 'the-message'; + + $event = new Skipped($telemetryInfo, $testSuite, $message); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + $this->assertSame($message, $event->message()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Skipped( + $this->telemetryInfo(), + $this->testSuiteValueObject(), + 'the-message', + ); + + $this->assertSame('Test Suite Skipped (foo, the-message)', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/SortedTest.php b/tests/unit/Event/Events/TestSuite/SortedTest.php new file mode 100644 index 00000000000..a8fe7aad296 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/SortedTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Sorted::class)] +#[Small] +final class SortedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $executionOrder = 9001; + $executionOrderDefects = 5; + $resolveDependencies = true; + + $event = new Sorted( + $telemetryInfo, + $executionOrder, + $executionOrderDefects, + $resolveDependencies, + ); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($executionOrder, $event->executionOrder()); + $this->assertSame($executionOrderDefects, $event->executionOrderDefects()); + $this->assertSame($resolveDependencies, $event->resolveDependencies()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Sorted( + $this->telemetryInfo(), + 9001, + 5, + true, + ); + + $this->assertSame('Test Suite Sorted', $event->asString()); + } +} diff --git a/tests/unit/Event/Events/TestSuite/StartedTest.php b/tests/unit/Event/Events/TestSuite/StartedTest.php new file mode 100644 index 00000000000..11a7e2046a6 --- /dev/null +++ b/tests/unit/Event/Events/TestSuite/StartedTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\AbstractEventTestCase; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Started::class)] +#[Small] +final class StartedTest extends AbstractEventTestCase +{ + public function testConstructorSetsValues(): void + { + $telemetryInfo = $this->telemetryInfo(); + $testSuite = $this->testSuiteValueObject(); + + $event = new Started($telemetryInfo, $testSuite); + + $this->assertSame($telemetryInfo, $event->telemetryInfo()); + $this->assertSame($testSuite, $event->testSuite()); + } + + public function testCanBeRepresentedAsString(): void + { + $event = new Started( + $this->telemetryInfo(), + $this->testSuiteValueObject(), + ); + + $this->assertSame('Test Suite Started (foo, 9001 tests)', $event->asString()); + } +} diff --git a/tests/unit/Event/FacadeTest.php b/tests/unit/Event/FacadeTest.php new file mode 100644 index 00000000000..42d4df6dcb0 --- /dev/null +++ b/tests/unit/Event/FacadeTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Event\Tracer\Tracer; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Facade::class)] +#[Small] +final class FacadeTest extends TestCase +{ + public function testSubscriberRegistrationDoesNotWorkWhenEventFacadeIsSealed(): void + { + $this->expectException(EventFacadeIsSealedException::class); + + Facade::instance()->registerSubscriber( + new class implements Subscriber + {}, + ); + } + + public function testTracerRegistrationDoesNotWorkWhenEventFacadeIsSealed(): void + { + $this->expectException(EventFacadeIsSealedException::class); + + Facade::instance()->registerTracer( + new class implements Tracer + { + public function trace(Event $event): void + { + } + }, + ); + } +} diff --git a/tests/unit/Event/TypeMapTest.php b/tests/unit/Event/TypeMapTest.php new file mode 100644 index 00000000000..e641c7835f3 --- /dev/null +++ b/tests/unit/Event/TypeMapTest.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\AnotherDummySubscriber; +use PHPUnit\TestFixture\DummyEvent; +use PHPUnit\TestFixture\DummySubscriber; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\FinalClass; + +#[CoversClass(TypeMap::class)] +#[Small] +final class TypeMapTest extends TestCase +{ + public function testMapsKnownSubscriberInterfaceToEventClass(): void + { + $subscriber = $this->createStub(DummySubscriber::class); + $subscriberType = DummySubscriber::class; + $event = new DummyEvent; + $eventType = DummyEvent::class; + + $map = new TypeMap; + + $this->assertFalse($map->isKnownSubscriberType($subscriber)); + $this->assertFalse($map->isKnownEventType($event)); + + $map->addMapping($subscriberType, $eventType); + + $this->assertTrue($map->isKnownSubscriberType($subscriber)); + $this->assertTrue($map->isKnownEventType($event)); + + $this->assertSame($eventType, $map->map($subscriber)); + } + + public function testCannotMapUnknownSubscriberInterface(): void + { + $subscriber = $this->createStub(DummySubscriber::class); + + $map = new TypeMap; + + $this->expectException(MapError::class); + + $map->map($subscriber); + } + + public function testCannotAddMappingFromUnknownSubscriberInterface(): void + { + $subscriberType = 'DoesNotExist'; + $eventType = DummyEvent::class; + + $map = new TypeMap; + + $this->expectException(UnknownSubscriberException::class); + + $map->addMapping($subscriberType, $eventType); + } + + public function testCannotAddMappingFromInvalidSubscriberInterface(): void + { + $subscriberType = AnInterface::class; + $eventType = DummyEvent::class; + + $map = new TypeMap; + + $this->expectException(InvalidSubscriberException::class); + + $map->addMapping($subscriberType, $eventType); + } + + public function testCannotAddMappingToUnknownEventClass(): void + { + $subscriberType = DummySubscriber::class; + $eventType = 'DoesNotExist'; + + $map = new TypeMap; + + $this->expectException(UnknownEventException::class); + + $map->addMapping($subscriberType, $eventType); + } + + public function testCannotAddMappingToInvalidEventClass(): void + { + $subscriberType = DummySubscriber::class; + $eventType = FinalClass::class; + + $map = new TypeMap; + + $this->expectException(InvalidEventException::class); + + $map->addMapping($subscriberType, $eventType); + } + + public function testSubscriberInterfaceCanOnlyBeRegisteredOnce(): void + { + $subscriberType = DummySubscriber::class; + $eventType = DummyEvent::class; + + $map = new TypeMap; + + $map->addMapping($subscriberType, $eventType); + + $this->expectException(SubscriberTypeAlreadyRegisteredException::class); + + $map->addMapping($subscriberType, $eventType); + } + + public function testEventClassCanOnlyBeRegisteredOnce(): void + { + $subscriberType = DummySubscriber::class; + $anotherSubscriberType = AnotherDummySubscriber::class; + $eventType = DummyEvent::class; + + $map = new TypeMap; + + $map->addMapping($subscriberType, $eventType); + + $this->expectException(EventAlreadyAssignedException::class); + + $map->addMapping($anotherSubscriberType, $eventType); + } +} diff --git a/tests/unit/Event/Value/ClassMethodTest.php b/tests/unit/Event/Value/ClassMethodTest.php new file mode 100644 index 00000000000..97594c3d2b5 --- /dev/null +++ b/tests/unit/Event/Value/ClassMethodTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ClassMethod::class)] +#[Small] +final class ClassMethodTest extends TestCase +{ + public function testConstructorSetsValues(): void + { + $className = self::class; + $methodName = 'foo'; + + $classMethod = new ClassMethod( + $className, + $methodName, + ); + + $this->assertSame($className, $classMethod->className()); + $this->assertSame($methodName, $classMethod->methodName()); + } +} diff --git a/tests/unit/Event/Value/ComparisonFailureBuilderTest.php b/tests/unit/Event/Value/ComparisonFailureBuilderTest.php new file mode 100644 index 00000000000..ff7f2f15b4c --- /dev/null +++ b/tests/unit/Event/Value/ComparisonFailureBuilderTest.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use SebastianBergmann\Comparator\ComparisonFailure; +use stdClass; + +#[CoversClass(ComparisonFailureBuilder::class)] +#[Small] +final class ComparisonFailureBuilderTest extends TestCase +{ + public static function provider(): array + { + return [ + 'type of expected value: string, string representation of expected value: not available, type of actual value: string, string representation of actual value: not available' => [ + 'expected', + 'actual', + '', + new ExpectationFailedException( + 'message', + new ComparisonFailure( + 'expected', + 'actual', + '', + '', + 'message', + ), + ), + ], + + 'type of expected value: true, string representation of expected value: not available, type of actual value: false, string representation of actual value: not available' => [ + 'true', + 'false', + '', + new ExpectationFailedException( + 'message', + new ComparisonFailure( + true, + false, + '', + '', + 'message', + ), + ), + ], + + 'type of expected value: null, string representation of expected value: not available, type of actual value: null, string representation of actual value: not available' => [ + 'null', + 'null', + '', + new ExpectationFailedException( + 'message', + new ComparisonFailure( + null, + null, + '', + '', + 'message', + ), + ), + ], + + 'type of expected value: array, string representation of expected value: not available, type of actual value: object, string representation of actual value: not available' => [ + '', + '', + '', + new ExpectationFailedException( + 'message', + new ComparisonFailure( + [], + new stdClass, + '', + '', + 'message', + ), + ), + ], + + 'type of expected value: string, string representation of expected value: available, type of actual value: string, string representation of actual value: available' => [ + 'expected-string', + 'actual-string', + <<<'EOT' + +--- Expected ++++ Actual +@@ @@ +-expected-string ++actual-string + +EOT, + new ExpectationFailedException( + 'message', + new ComparisonFailure( + 'expected', + 'actual', + 'expected-string', + 'actual-string', + 'message', + ), + ), + ], + ]; + } + + #[TestDox('Maps exception that is not of type ExpectationFailedException to null')] + public function testMapsGenericThrowableToNull(): void + { + $this->assertNull( + ComparisonFailureBuilder::from(new Exception), + ); + } + + #[TestDox('Maps ExpectationFailedException that does not aggregate a ComparisonFailure object to null')] + public function testMapsExpectationFailedExceptionWithoutComparisonFailureToNull(): void + { + $this->assertNull( + ComparisonFailureBuilder::from( + new ExpectationFailedException('message'), + ), + ); + } + + #[DataProvider('provider')] + #[TestDox('Maps ExpectationFailedException that aggregates a ComparisonFailure object to value object')] + public function testMapsExpectationFailedExceptionWithComparisonFailureToValueObject(string $expected, string $actual, string $diff, ExpectationFailedException $exception): void + { + $comparisonFailure = ComparisonFailureBuilder::from($exception); + + $this->assertSame($expected, $comparisonFailure->expected()); + $this->assertSame($actual, $comparisonFailure->actual()); + $this->assertSame($diff, $comparisonFailure->diff()); + } +} diff --git a/tests/unit/Event/Value/ComparisonFailureTest.php b/tests/unit/Event/Value/ComparisonFailureTest.php new file mode 100644 index 00000000000..d7d8ad35ade --- /dev/null +++ b/tests/unit/Event/Value/ComparisonFailureTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ComparisonFailure::class)] +#[Small] +final class ComparisonFailureTest extends TestCase +{ + public function testConstructorSetsValues(): void + { + $expected = 'expected'; + $actual = 'actual'; + $diff = 'diff'; + + $comparisonFailure = new ComparisonFailure($expected, $actual, $diff); + + $this->assertSame($expected, $comparisonFailure->expected()); + $this->assertSame($actual, $comparisonFailure->actual()); + $this->assertSame($diff, $comparisonFailure->diff()); + } +} diff --git a/tests/unit/Event/Value/Runtime/OperatingSystemTest.php b/tests/unit/Event/Value/Runtime/OperatingSystemTest.php new file mode 100644 index 00000000000..5dc91a33961 --- /dev/null +++ b/tests/unit/Event/Value/Runtime/OperatingSystemTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_OS; +use const PHP_OS_FAMILY; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(OperatingSystem::class)] +#[Small] +final class OperatingSystemTest extends TestCase +{ + public function testCanBeRepresentedAsString(): void + { + $this->assertSame(PHP_OS, (new OperatingSystem)->operatingSystem()); + } + + public function testHasOperatingSystemFamily(): void + { + $this->assertSame(PHP_OS_FAMILY, (new OperatingSystem)->operatingSystemFamily()); + } +} diff --git a/tests/unit/Event/Value/Runtime/PHPTest.php b/tests/unit/Event/Value/Runtime/PHPTest.php new file mode 100644 index 00000000000..061d3d8c2b1 --- /dev/null +++ b/tests/unit/Event/Value/Runtime/PHPTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use const PHP_EXTRA_VERSION; +use const PHP_MAJOR_VERSION; +use const PHP_MINOR_VERSION; +use const PHP_RELEASE_VERSION; +use const PHP_SAPI; +use const PHP_VERSION; +use const PHP_VERSION_ID; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(PHP::class)] +#[Small] +final class PHPTest extends TestCase +{ + public function testHasVersion(): void + { + $this->assertSame(PHP_VERSION, (new PHP)->version()); + } + + public function testHasVersionId(): void + { + $this->assertSame(PHP_VERSION_ID, (new PHP)->versionId()); + } + + public function testHasMajorVersion(): void + { + $this->assertSame(PHP_MAJOR_VERSION, (new PHP)->majorVersion()); + } + + public function testHasMinorVersion(): void + { + $this->assertSame(PHP_MINOR_VERSION, (new PHP)->minorVersion()); + } + + public function testHasReleaseVersion(): void + { + $this->assertSame(PHP_RELEASE_VERSION, (new PHP)->releaseVersion()); + } + + public function testHasExtraVersion(): void + { + $this->assertSame(PHP_EXTRA_VERSION, (new PHP)->extraVersion()); + } + + public function testHasSapi(): void + { + $this->assertSame(PHP_SAPI, (new PHP)->sapi()); + } + + public function testHasExtensions(): void + { + $this->assertNotEmpty((new PHP)->extensions()); + $this->assertIsList((new PHP)->extensions()); + $this->assertContainsOnlyString((new PHP)->extensions()); + } +} diff --git a/tests/unit/Event/Value/Runtime/PHPUnitTest.php b/tests/unit/Event/Value/Runtime/PHPUnitTest.php new file mode 100644 index 00000000000..b9f479bf2d5 --- /dev/null +++ b/tests/unit/Event/Value/Runtime/PHPUnitTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Version; + +#[CoversClass(PHPUnit::class)] +#[Small] +final class PHPUnitTest extends TestCase +{ + public function testHasVersionId(): void + { + $this->assertSame(Version::id(), (new PHPUnit)->versionId()); + } + + public function testHasReleaseSeries(): void + { + $this->assertSame(Version::series(), (new PHPUnit)->releaseSeries()); + } +} diff --git a/tests/unit/Event/Value/Runtime/RuntimeTest.php b/tests/unit/Event/Value/Runtime/RuntimeTest.php new file mode 100644 index 00000000000..bb28d5b98f5 --- /dev/null +++ b/tests/unit/Event/Value/Runtime/RuntimeTest.php @@ -0,0 +1,52 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Runtime; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Runtime::class)] +#[UsesClass(OperatingSystem::class)] +#[UsesClass(PHP::class)] +#[UsesClass(PHPUnit::class)] +#[Small] +final class RuntimeTest extends TestCase +{ + public function testHasOperatingSystem(): void + { + $operatingSystem = new OperatingSystem; + + $this->assertSame($operatingSystem->operatingSystem(), (new Runtime)->operatingSystem()->operatingSystem()); + } + + public function test_has_PHP(): void + { + $php = new PHP; + + $this->assertSame($php->version(), (new Runtime)->php()->version()); + } + + public function test_has_PHPUnit(): void + { + $phpunit = new PHPUnit; + + $this->assertSame($phpunit->versionId(), (new Runtime)->phpunit()->versionId()); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertStringMatchesFormat( + 'PHPUnit %s using PHP %s (%s) on %s', + (new Runtime)->asString(), + ); + } +} diff --git a/tests/unit/Event/Value/Telemetry/DurationTest.php b/tests/unit/Event/Value/Telemetry/DurationTest.php new file mode 100644 index 00000000000..5d4a5206d36 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/DurationTest.php @@ -0,0 +1,201 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Duration::class)] +#[Small] +final class DurationTest extends TestCase +{ + /** + * @return array + */ + public static function provideDurationAndStringRepresentation(): array + { + return [ + 'less than a minute' => [ + '00:00:59.000000123', + 59, + 123, + ], + + 'less than an hour' => [ + '00:59:19.000000123', + 3559, + 123, + ], + + 'more than an hour' => [ + '01:00:01.000000123', + 3601, + 123, + ], + ]; + } + + public function testCanBeCreatedFromSecondsAndNanoseconds(): void + { + $seconds = 123; + $nanoseconds = 999999999; + + $duration = Duration::fromSecondsAndNanoseconds($seconds, $nanoseconds); + + $this->assertSame($seconds, $duration->seconds()); + $this->assertSame($nanoseconds, $duration->nanoseconds()); + } + + public function testSecondsMustNotBeNegative(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for seconds must not be negative'); + + Duration::fromSecondsAndNanoseconds(-1, 0); + } + + public function testNanosecondsMustNotBeNegative(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for nanoseconds must not be negative'); + + Duration::fromSecondsAndNanoseconds(0, -1); + } + + public function testNanosecondsMustNotBeGreaterThan999999999(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for nanoseconds must not be greater than 999999999'); + + Duration::fromSecondsAndNanoseconds(0, 1000000000); + } + + #[DataProvider('provideDurationAndStringRepresentation')] + #[TestDox('$seconds seconds and $nanoseconds nanoseconds is represented as "$expected"')] + public function testCanBeRepresentedAsString(string $expected, int $seconds, int $nanoseconds): void + { + $this->assertSame( + $expected, + (Duration::fromSecondsAndNanoseconds($seconds, $nanoseconds))->asString(), + ); + } + + public function testCanBeRepresentedAsFloat(): void + { + $this->assertSame(0.0, Duration::fromSecondsAndNanoseconds(0, 0)->asFloat()); + } + + public function testEqualsReturnsFalseWhenValuesAreDifferent(): void + { + $one = Duration::fromSecondsAndNanoseconds( + 123, + 456, + ); + + $two = Duration::fromSecondsAndNanoseconds( + 456, + 123, + ); + + $this->assertFalse($one->equals($two)); + } + + public function testEqualsReturnsTrueWhenValuesAreSame(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 456); + + $this->assertTrue($one->equals($two)); + } + + public function testIsLessThanReturnsFalseWhenSecondsAreGreater(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(122, 456); + + $this->assertFalse($one->isLessThan($two)); + } + + public function testIsLessThanReturnsFalseWhenSecondsAreEqualAndNanosecondsAreGreater(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 455); + + $this->assertFalse($one->isLessThan($two)); + } + + public function testIsLessThanReturnsFalseWhenValuesAreSame(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 456); + + $this->assertFalse($one->isLessThan($two)); + } + + public function testIsLessThanReturnsTrueWhenSecondsAreLess(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(124, 456); + + $this->assertTrue($one->isLessThan($two)); + } + + public function testIsLessThanReturnsTrueWhenSecondsAreEqualAndNanosecondsAreLess(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 457); + + $this->assertTrue($one->isLessThan($two)); + } + + public function testIsGreaterThanReturnsFalseWhenSecondsAreLess(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(124, 456); + + $this->assertFalse($one->isGreaterThan($two)); + } + + public function testIsGreaterThanReturnsFalseWhenSecondsAreEqualAndNanosecondsAreLess(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 457); + + $this->assertFalse($one->isGreaterThan($two)); + } + + public function testIsGreaterThanReturnsFalseWhenValuesAreSame(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 456); + + $this->assertFalse($one->isGreaterThan($two)); + } + + public function testIsGreaterThanReturnsTrueWhenSecondsAreGreater(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(122, 456); + + $this->assertTrue($one->isGreaterThan($two)); + } + + public function testIsGreaterThanReturnsTrueWhenSecondsAreEqualAndNanosecondsAreGreater(): void + { + $one = Duration::fromSecondsAndNanoseconds(123, 456); + $two = Duration::fromSecondsAndNanoseconds(123, 455); + + $this->assertTrue($one->isGreaterThan($two)); + } +} diff --git a/tests/unit/Event/Value/Telemetry/GarbageCollectorStatusTest.php b/tests/unit/Event/Value/Telemetry/GarbageCollectorStatusTest.php new file mode 100644 index 00000000000..608bdaaec55 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/GarbageCollectorStatusTest.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(GarbageCollectorStatus::class)] +#[Small] +final class GarbageCollectorStatusTest extends TestCase +{ + public function testHasRuns(): void + { + $this->assertSame(1, $this->garbageCollectorStatus()->runs()); + } + + public function testHasCollected(): void + { + $this->assertSame(2, $this->garbageCollectorStatus()->collected()); + } + + public function testHasThreshold(): void + { + $this->assertSame(3, $this->garbageCollectorStatus()->threshold()); + } + + public function testHasRoots(): void + { + $this->assertSame(4, $this->garbageCollectorStatus()->roots()); + } + + public function testMayHaveRunning(): void + { + $this->assertTrue($this->garbageCollectorStatus()->isRunning()); + } + + public function testMayHaveApplicationTime(): void + { + $this->assertSame(5.0, $this->garbageCollectorStatus()->applicationTime()); + } + + public function testMayHaveCollectorTime(): void + { + $this->assertSame(6.0, $this->garbageCollectorStatus()->collectorTime()); + } + + public function testMayHaveDestructorTime(): void + { + $this->assertSame(7.0, $this->garbageCollectorStatus()->destructorTime()); + } + + public function testMayHaveFreeTime(): void + { + $this->assertSame(8.0, $this->garbageCollectorStatus()->freeTime()); + } + + public function testMayHaveProtected(): void + { + $this->assertTrue($this->garbageCollectorStatus()->isProtected()); + } + + public function testMayHaveFull(): void + { + $this->assertTrue($this->garbageCollectorStatus()->isFull()); + } + + public function testMayHaveBufferSize(): void + { + $this->assertSame(9, $this->garbageCollectorStatus()->bufferSize()); + } + + private function garbageCollectorStatus(): GarbageCollectorStatus + { + return new GarbageCollectorStatus( + 1, + 2, + 3, + 4, + 5.0, + 6.0, + 7.0, + 8.0, + true, + true, + true, + 9, + ); + } +} diff --git a/tests/unit/Event/Value/Telemetry/HRTimeTest.php b/tests/unit/Event/Value/Telemetry/HRTimeTest.php new file mode 100644 index 00000000000..5ac5da9d65e --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/HRTimeTest.php @@ -0,0 +1,160 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(HRTime::class)] +#[Small] +final class HRTimeTest extends TestCase +{ + /** + * @return array + */ + public static function provideStartGreaterThanEnd(): array + { + return [ + 'seconds-greater' => [ + 11, + 1, + 10, + 1, + ], + 'seconds-and-nanoseconds-greater' => [ + 11, + 1, + 10, + 0, + ], + 'nanoseconds-greater' => [ + 10, + 1, + 10, + 0, + ], + ]; + } + + /** + * @return array + */ + public static function provideStartEndAndDuration(): array + { + return [ + 'start-equal-to-end' => [ + 10, + 50, + 10, + 50, + Duration::fromSecondsAndNanoseconds(0, 0), + ], + 'start-smaller-than-end' => [ + 10, + 50, + 12, + 70, + Duration::fromSecondsAndNanoseconds(2, 20), + ], + 'start-nanoseconds-greater-than-end-nanoseconds' => [ + 10, + 50, + 12, + 30, + Duration::fromSecondsAndNanoseconds(1, 999999980), + ], + ]; + } + + public function testFromSecondsAndNanosecondsRejectsNegativeSeconds(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for seconds must not be negative'); + + HRTime::fromSecondsAndNanoseconds( + -1, + 0, + ); + } + + public function testFromSecondsAndNanosecondsRejectsNegativeNanoseconds(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for nanoseconds must not be negative'); + + HRTime::fromSecondsAndNanoseconds( + 0, + -1, + ); + } + + public function testFromSecondsAndNanosecondsRejectsNanosecondsGreaterThan999999999(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Value for nanoseconds must not be greater than 999999999'); + + HRTime::fromSecondsAndNanoseconds( + 0, + 1000000000, + ); + } + + public function testFromSecondsAndNanosecondsReturnsHRTime(): void + { + $seconds = 123; + $nanoseconds = 456; + + $time = HRTime::fromSecondsAndNanoseconds( + $seconds, + $nanoseconds, + ); + + $this->assertSame($seconds, $time->seconds()); + $this->assertSame($nanoseconds, $time->nanoseconds()); + } + + #[DataProvider('provideStartGreaterThanEnd')] + public function testDurationIgnoresStartGreaterThanEnd(int $startSeconds, int $startNanoseconds, int $endSeconds, int $endNanoseconds): void + { + $start = HRTime::fromSecondsAndNanoseconds( + $startSeconds, + $startNanoseconds, + ); + + $end = HRTime::fromSecondsAndNanoseconds( + $endSeconds, + $endNanoseconds, + ); + + $duration = $end->duration($start); + + $this->assertSame(0, $duration->seconds()); + $this->assertSame(0, $duration->nanoseconds()); + } + + #[DataProvider('provideStartEndAndDuration')] + public function testDurationReturnsDifferenceBetweenEndAndStart(int $startSeconds, int $startNanoseconds, int $endSeconds, int $endNanoseconds, Duration $duration): void + { + $start = HRTime::fromSecondsAndNanoseconds( + $startSeconds, + $startNanoseconds, + ); + + $end = HRTime::fromSecondsAndNanoseconds( + $endSeconds, + $endNanoseconds, + ); + + $this->assertEquals($duration, $end->duration($start)); + } +} diff --git a/tests/unit/Event/Value/Telemetry/InfoTest.php b/tests/unit/Event/Value/Telemetry/InfoTest.php new file mode 100644 index 00000000000..1bec91ff83c --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/InfoTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Info::class)] +#[Small] +final class InfoTest extends TestCase +{ + public function testHasTime(): void + { + $this->assertInstanceOf(HRTime::class, $this->info()->time()); + } + + public function testHasMemoryUsage(): void + { + $this->assertInstanceOf(MemoryUsage::class, $this->info()->memoryUsage()); + } + + public function testHasPeakMemoryUsage(): void + { + $this->assertInstanceOf(MemoryUsage::class, $this->info()->peakMemoryUsage()); + } + + public function testHasDurationSinceStart(): void + { + $this->assertSame(0, $this->info()->durationSinceStart()->nanoseconds()); + } + + public function testHasDurationSincePrevious(): void + { + $this->assertSame(0, $this->info()->durationSincePrevious()->nanoseconds()); + } + + public function testHasMemoryUsageSinceStart(): void + { + $this->assertSame(0, $this->info()->memoryUsageSinceStart()->bytes()); + } + + public function testHasMemoryUsageSincePrevious(): void + { + $this->assertSame(0, $this->info()->memoryUsageSincePrevious()->bytes()); + } + + public function testHasGarbageCollectorStatus(): void + { + $this->assertInstanceOf(GarbageCollectorStatus::class, $this->info()->garbageCollectorStatus()); + } + + public function testCanBeFormattedAsString(): void + { + $this->assertStringMatchesFormat( + '[00:00:00.000000000 / 00:00:00.000000000] [%d bytes]', + $this->info()->asString(), + ); + } + + private function info(): Info + { + $current = $this->telemetrySystem()->snapshot(); + + return new Info( + $current, + $current->time()->duration($current->time()), + $current->memoryUsage()->diff($current->memoryUsage()), + $current->time()->duration($current->time()), + $current->memoryUsage()->diff($current->memoryUsage()), + ); + } + + private function telemetrySystem(): System + { + return new System( + new SystemStopWatch, + new SystemMemoryMeter, + new SystemGarbageCollectorStatusProvider, + ); + } +} diff --git a/tests/unit/Event/Value/Telemetry/MemoryUsageTest.php b/tests/unit/Event/Value/Telemetry/MemoryUsageTest.php new file mode 100644 index 00000000000..89b32e1ae99 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/MemoryUsageTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(MemoryUsage::class)] +#[Small] +final class MemoryUsageTest extends TestCase +{ + public static function provideValidBytes(): array + { + return [ + 'int-less-than-zero' => [-1], + 'int-zero' => [0], + 'int-greater-than-zero' => [1], + ]; + } + + #[DataProvider('provideValidBytes')] + public function testFromBytesReturnsMemoryUsage(int $bytes): void + { + $memoryUsage = MemoryUsage::fromBytes($bytes); + + $this->assertSame($bytes, $memoryUsage->bytes()); + } + + public function testDiffReturnsMemoryUsage(): void + { + $one = MemoryUsage::fromBytes(2000); + $two = MemoryUsage::fromBytes(3000); + + $diff = $one->diff($two); + + $this->assertNotSame($one, $diff); + $this->assertNotSame($two, $diff); + $this->assertSame($one->bytes() - $two->bytes(), $diff->bytes()); + } +} diff --git a/tests/unit/Event/Value/Telemetry/SnapshotTest.php b/tests/unit/Event/Value/Telemetry/SnapshotTest.php new file mode 100644 index 00000000000..cb88993b982 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/SnapshotTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Snapshot::class)] +#[Small] +final class SnapshotTest extends TestCase +{ + public function testConstructorSetsValues(): void + { + $time = HRTime::fromSecondsAndNanoseconds(...hrtime(false)); + $memoryUsage = MemoryUsage::fromBytes(2000); + $peakMemoryUsage = MemoryUsage::fromBytes(3000); + $garbageCollectorStatus = new GarbageCollectorStatus(0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, false, false, false, 0); + + $snapshot = new Snapshot( + $time, + $memoryUsage, + $peakMemoryUsage, + $garbageCollectorStatus, + ); + + $this->assertSame($time, $snapshot->time()); + $this->assertSame($memoryUsage, $snapshot->memoryUsage()); + $this->assertSame($peakMemoryUsage, $snapshot->peakMemoryUsage()); + $this->assertSame($garbageCollectorStatus, $snapshot->garbageCollectorStatus()); + } +} diff --git a/tests/unit/Event/Value/Telemetry/SystemStopWatchTest.php b/tests/unit/Event/Value/Telemetry/SystemStopWatchTest.php new file mode 100644 index 00000000000..07efe574f89 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/SystemStopWatchTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SystemStopWatch::class)] +#[Small] +final class SystemStopWatchTest extends TestCase +{ + public function testNowReturnsDateTimeImmutable(): void + { + $clock = new SystemStopWatch; + + $before = HRTime::fromSecondsAndNanoseconds(...hrtime(false)); + + $current = $clock->current(); + + $after = HRTime::fromSecondsAndNanoseconds(...hrtime(false)); + + $durationBetweenCurrentAndBefore = $current->duration($before); + + $this->assertSame(0, $durationBetweenCurrentAndBefore->seconds()); + $this->assertGreaterThan(0, $durationBetweenCurrentAndBefore->nanoseconds()); + + $durationBetweenAfterAndCurrent = $after->duration($current); + + $this->assertSame(0, $durationBetweenAfterAndCurrent->seconds()); + $this->assertGreaterThan(0, $durationBetweenAfterAndCurrent->nanoseconds()); + } +} diff --git a/tests/unit/Event/Value/Telemetry/SystemTest.php b/tests/unit/Event/Value/Telemetry/SystemTest.php new file mode 100644 index 00000000000..a3fef4ed9d5 --- /dev/null +++ b/tests/unit/Event/Value/Telemetry/SystemTest.php @@ -0,0 +1,89 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Telemetry; + +use function hrtime; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(System::class)] +#[Small] +final class SystemTest extends TestCase +{ + public function testSnapshotReturnsSnapshot(): void + { + $time = HRTime::fromSecondsAndNanoseconds(...hrtime(false)); + + $clock = new class($time) implements StopWatch + { + private readonly HRTime $time; + + public function __construct(HRTime $time) + { + $this->time = $time; + } + + public function current(): HRTime + { + return $this->time; + } + }; + + $memoryUsage = MemoryUsage::fromBytes(2000); + $peakMemoryUsage = MemoryUsage::fromBytes(3000); + + $memoryMeter = new class($memoryUsage, $peakMemoryUsage) implements MemoryMeter + { + private readonly MemoryUsage $memoryUsage; + private readonly MemoryUsage $peakMemoryUsage; + + public function __construct(MemoryUsage $memoryUsage, MemoryUsage $peakMemoryUsage) + { + $this->memoryUsage = $memoryUsage; + $this->peakMemoryUsage = $peakMemoryUsage; + } + + public function memoryUsage(): MemoryUsage + { + return $this->memoryUsage; + } + + public function peakMemoryUsage(): MemoryUsage + { + return $this->peakMemoryUsage; + } + }; + + $garbageCollectorStatus = new GarbageCollectorStatus(0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, false, false, false, 0); + + $garbageCollectorProvider = new class($garbageCollectorStatus) implements GarbageCollectorStatusProvider + { + private readonly GarbageCollectorStatus $status; + + public function __construct(GarbageCollectorStatus $status) + { + $this->status = $status; + } + + public function status(): GarbageCollectorStatus + { + return $this->status; + } + }; + + $snapshot = new System($clock, $memoryMeter, $garbageCollectorProvider)->snapshot(); + + $this->assertSame($time, $snapshot->time()); + $this->assertSame($memoryUsage, $snapshot->memoryUsage()); + $this->assertSame($peakMemoryUsage, $snapshot->peakMemoryUsage()); + $this->assertSame($garbageCollectorStatus, $snapshot->garbageCollectorStatus()); + } +} diff --git a/tests/unit/Event/Value/Test/IssueTriggerTest.php b/tests/unit/Event/Value/Test/IssueTriggerTest.php new file mode 100644 index 00000000000..cbfe4b4ac6d --- /dev/null +++ b/tests/unit/Event/Value/Test/IssueTriggerTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code\IssueTrigger; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IssueTrigger::class)] +#[CoversClassesThatExtendClass(IssueTrigger::class)] +#[Small] +final class IssueTriggerTest extends TestCase +{ + public function testCanBeTest(): void + { + $trigger = IssueTrigger::test(); + + $this->assertTrue($trigger->isTest()); + $this->assertFalse($trigger->isSelf()); + $this->assertFalse($trigger->isDirect()); + $this->assertFalse($trigger->isIndirect()); + $this->assertFalse($trigger->isUnknown()); + $this->assertSame('issue triggered by test code', $trigger->asString()); + } + + public function testCanBeSelf(): void + { + $trigger = IssueTrigger::self(); + + $this->assertTrue($trigger->isSelf()); + $this->assertFalse($trigger->isTest()); + $this->assertFalse($trigger->isDirect()); + $this->assertFalse($trigger->isIndirect()); + $this->assertFalse($trigger->isUnknown()); + $this->assertSame('issue triggered by first-party code calling into first-party code', $trigger->asString()); + } + + public function testCanBeDirect(): void + { + $trigger = IssueTrigger::direct(); + + $this->assertTrue($trigger->isDirect()); + $this->assertFalse($trigger->isTest()); + $this->assertFalse($trigger->isSelf()); + $this->assertFalse($trigger->isIndirect()); + $this->assertFalse($trigger->isUnknown()); + $this->assertSame('issue triggered by first-party code calling into third-party code', $trigger->asString()); + } + + public function testCanBeIndirect(): void + { + $trigger = IssueTrigger::indirect(); + + $this->assertTrue($trigger->isIndirect()); + $this->assertFalse($trigger->isTest()); + $this->assertFalse($trigger->isSelf()); + $this->assertFalse($trigger->isDirect()); + $this->assertFalse($trigger->isUnknown()); + $this->assertSame('issue triggered by third-party code', $trigger->asString()); + } + + public function testCanBeUnknown(): void + { + $trigger = IssueTrigger::unknown(); + + $this->assertFalse($trigger->isTest()); + $this->assertFalse($trigger->isSelf()); + $this->assertFalse($trigger->isDirect()); + $this->assertFalse($trigger->isIndirect()); + $this->assertTrue($trigger->isUnknown()); + $this->assertSame('unknown if issue was triggered in first-party code or third-party code', $trigger->asString()); + } +} diff --git a/tests/unit/Event/Value/Test/PhptTest.php b/tests/unit/Event/Value/Test/PhptTest.php new file mode 100644 index 00000000000..484c3ee8ba0 --- /dev/null +++ b/tests/unit/Event/Value/Test/PhptTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Phpt::class)] +#[CoversClass(Test::class)] +#[Small] +final class PhptTest extends TestCase +{ + public function testConstructorSetsValues(): void + { + $file = 'test.phpt'; + + $test = new Phpt($file); + + $this->assertSame($file, $test->file()); + $this->assertSame($file, $test->id()); + $this->assertSame($file, $test->name()); + $this->assertTrue($test->isPhpt()); + $this->assertFalse($test->isTestMethod()); + } +} diff --git a/tests/unit/Event/Value/Test/TestCollectionTest.php b/tests/unit/Event/Value/Test/TestCollectionTest.php new file mode 100644 index 00000000000..3b307b6dc7b --- /dev/null +++ b/tests/unit/Event/Value/Test/TestCollectionTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\MetadataCollection; + +#[CoversClass(TestCollection::class)] +#[CoversClass(TestCollectionIterator::class)] +#[Small] +final class TestCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $test = $this->test(); + $tests = TestCollection::fromArray([$test]); + + $this->assertSame([$test], $tests->asArray()); + } + + public function testIsCountable(): void + { + $test = $this->test(); + $tests = TestCollection::fromArray([$test]); + + $this->assertCount(1, $tests); + } + + public function testIsIterable(): void + { + $test = $this->test(); + $tests = TestCollection::fromArray([$test]); + + foreach ($tests as $index => $_test) { + $this->assertSame(0, $index); + $this->assertSame($test, $_test); + } + } + + private function test(): TestMethod + { + return new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } +} diff --git a/tests/unit/Event/Value/Test/TestData/TestDataCollectionTest.php b/tests/unit/Event/Value/Test/TestData/TestDataCollectionTest.php new file mode 100644 index 00000000000..2158c20f95c --- /dev/null +++ b/tests/unit/Event/Value/Test/TestData/TestDataCollectionTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestDataCollection::class)] +#[CoversClass(TestDataCollectionIterator::class)] +#[UsesClass(TestData::class)] +#[UsesClass(DataFromDataProvider::class)] +#[UsesClass(DataFromTestDependency::class)] +#[Small] +final class TestDataCollectionTest extends TestCase +{ + public function testMayBeEmpty(): void + { + $collection = TestDataCollection::fromArray([]); + + $this->assertCount(0, $collection); + $this->assertFalse($collection->hasDataFromDataProvider()); + } + + public function testMayContainDataFromDataProvider(): void + { + $data = $this->dataFromDataProvider(); + $collection = TestDataCollection::fromArray([$data]); + + $this->assertTrue($collection->hasDataFromDataProvider()); + $this->assertSame([$data], $collection->asArray()); + $this->assertSame($data, $collection->dataFromDataProvider()); + } + + public function testMayContainDataFromDependedUponTest(): void + { + $data = $this->dataFromDependedUponTest(); + $collection = TestDataCollection::fromArray([$data]); + + $this->assertFalse($collection->hasDataFromDataProvider()); + $this->assertSame([$data], $collection->asArray()); + } + + public function testExceptionIsRaisedWhenDataFromDataProviderIsAccessedButDoesNotExist(): void + { + $collection = TestDataCollection::fromArray([]); + + $this->expectException(NoDataSetFromDataProviderException::class); + + $collection->dataFromDataProvider(); + } + + public function testIsIterable(): void + { + $data = $this->dataFromDataProvider(); + $collection = TestDataCollection::fromArray([$data]); + + foreach ($collection as $index => $element) { + $this->assertSame(0, $index); + $this->assertSame($data, $element); + } + } + + private function dataFromDataProvider(): DataFromDataProvider + { + return DataFromDataProvider::from( + 'data-set-name', + 'data-as-string', + 'data-as-string-for-output', + ); + } + + private function dataFromDependedUponTest(): DataFromTestDependency + { + return DataFromTestDependency::from('data-as-string'); + } +} diff --git a/tests/unit/Event/Value/Test/TestData/TestDataTest.php b/tests/unit/Event/Value/Test/TestData/TestDataTest.php new file mode 100644 index 00000000000..ee1db09b0a0 --- /dev/null +++ b/tests/unit/Event/Value/Test/TestData/TestDataTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestData; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestData::class)] +#[CoversClassesThatExtendClass(TestData::class)] +#[Small] +final class TestDataTest extends TestCase +{ + public function testDataCanBeFromDataProvider(): void + { + $name = 'data-set-name'; + $dataAsString = 'data-as-string'; + $dataAsStringForOutput = 'data-as-string-for-output'; + + $data = DataFromDataProvider::from( + $name, + $dataAsString, + $dataAsStringForOutput, + ); + + $this->assertTrue($data->isFromDataProvider()); + $this->assertFalse($data->isFromTestDependency()); + $this->assertSame($name, $data->dataSetName()); + $this->assertSame($dataAsString, $data->data()); + $this->assertSame($dataAsStringForOutput, $data->dataAsStringForResultOutput()); + } + + public function testDataCanBeFromDependedUponTest(): void + { + $dataAsString = 'data-as-string'; + + $data = DataFromTestDependency::from($dataAsString); + + $this->assertTrue($data->isFromTestDependency()); + $this->assertFalse($data->isFromDataProvider()); + $this->assertSame($dataAsString, $data->data()); + } +} diff --git a/tests/unit/Event/Value/Test/TestMethodTest.php b/tests/unit/Event/Value/Test/TestMethodTest.php new file mode 100644 index 00000000000..e87dc676132 --- /dev/null +++ b/tests/unit/Event/Value/Test/TestMethodTest.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use function sprintf; +use PHPUnit\Event\TestData\DataFromDataProvider; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\MetadataCollection; + +#[CoversClass(TestMethod::class)] +#[CoversClass(Test::class)] +#[Small] +final class TestMethodTest extends TestCase +{ + public function testConstructorSetsValues(): void + { + $className = 'FooTest'; + $methodName = 'testBar'; + $file = 'FooTest.php'; + $line = 1; + $testDox = TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'); + $testData = TestDataCollection::fromArray([]); + $metadata = MetadataCollection::fromArray([]); + + $test = new TestMethod( + $className, + $methodName, + $file, + $line, + $testDox, + $metadata, + $testData, + ); + + $this->assertSame($className, $test->className()); + $this->assertSame($methodName, $test->methodName()); + $this->assertSame($className . '::' . $methodName, $test->nameWithClass()); + $this->assertSame('FooTest::testBar', $test->id()); + $this->assertSame($file, $test->file()); + $this->assertSame($line, $test->line()); + $this->assertSame($testDox, $test->testDox()); + $this->assertSame($metadata, $test->metadata()); + $this->assertSame($testData, $test->testData()); + $this->assertTrue($test->isTestMethod()); + $this->assertFalse($test->isPhpt()); + } + + public function testNameReturnsNameWhenTestDoesNotHaveDataFromDataProvider(): void + { + $test = new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + + $this->assertSame($test->methodName(), $test->name()); + } + + public function testNameReturnsNameWhenTestHasDataFromDataProviderAndDataSetNameIsInt(): void + { + $dataSetName = 9000; + + $test = new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray( + [ + DataFromDataProvider::from( + $dataSetName, + 'data', + 'data as string for result output', + ), + ], + ), + ); + + $expected = sprintf( + '%s with data set #%d', + $test->methodName(), + $dataSetName, + ); + + $this->assertSame($expected, $test->name()); + $this->assertSame('FooTest::testBar#9000', $test->id()); + $this->assertSame('data', $test->testData()->dataFromDataProvider()->data()); + $this->assertSame('data as string for result output', $test->testData()->dataFromDataProvider()->dataAsStringForResultOutput()); + } + + public function testNameReturnsNameWhenTestHasDataFromDataProviderAndDataSetNameIsString(): void + { + $dataSetName = 'bar-9000'; + + $test = new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray( + [ + DataFromDataProvider::from( + $dataSetName, + 'data', + 'data as string for result output', + ), + ], + ), + ); + + $expected = sprintf( + '%s with data set "%s"', + $test->methodName(), + $dataSetName, + ); + + $this->assertSame($expected, $test->name()); + $this->assertSame('FooTest::testBar#bar-9000', $test->id()); + $this->assertSame('data', $test->testData()->dataFromDataProvider()->data()); + $this->assertSame('data as string for result output', $test->testData()->dataFromDataProvider()->dataAsStringForResultOutput()); + } +} diff --git a/tests/unit/Event/Value/TestSuite/TestSuiteBuilderTest.php b/tests/unit/Event/Value/TestSuite/TestSuiteBuilderTest.php new file mode 100644 index 00000000000..5e795790483 --- /dev/null +++ b/tests/unit/Event/Value/TestSuite/TestSuiteBuilderTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite as FrameworkTestSuite; +use PHPUnit\Runner\Filter\Factory; +use PHPUnit\TextUI\CliArguments\Builder as CliArgumentsBuilder; +use PHPUnit\TextUI\Configuration\Merger as ConfigurationMerger; +use PHPUnit\TextUI\XmlConfiguration\Loader as XmlConfigurationLoader; +use PHPUnit\TextUI\XmlConfiguration\TestSuiteMapper; + +#[CoversClass(TestSuiteBuilder::class)] +#[Small] +final class TestSuiteBuilderTest extends TestCase +{ + public function test_Builds_TestSuite_value_object_for_test_suite_loaded_from_XML_configuration_file(): void + { + $testSuite = TestSuiteBuilder::from($this->testSuiteFromXmlConfiguration()); + + $this->assertTrue($testSuite->isWithName()); + $this->assertStringEndsWith('phpunit.xml', $testSuite->name()); + $this->assertSame(3, $testSuite->count()); + $this->assertSame(3, $testSuite->tests()->count()); + $this->assertCount(3, $testSuite->tests()); + } + + public function testBuildCountWithFilter(): void + { + $testSuite = $this->testSuiteFromXmlConfiguration(); + $filterFactory = new Factory; + $filterFactory->addIncludeNameFilter('one'); + $testSuite->injectFilter($filterFactory); + $testSuite = TestSuiteBuilder::from($testSuite); + + $this->assertSame(1, $testSuite->count()); + $this->assertSame(1, $testSuite->tests()->count()); + $this->assertCount(1, $testSuite->tests()); + } + + public function test_Builds_TestSuite_value_object_for_test_case_class(): void + { + $testSuite = TestSuiteBuilder::from($this->testSuiteFromXmlConfiguration()->tests()[0]->tests()[0]); + + $this->assertTrue($testSuite->isForTestClass()); + $this->assertSame('PHPUnit\TestFixture\Groups\FooTest', $testSuite->name()); + $this->assertSame(3, $testSuite->count()); + $this->assertCount(3, $testSuite->tests()); + } + + private function testSuiteFromXmlConfiguration(): FrameworkTestSuite + { + $cliConfiguration = (new CliArgumentsBuilder)->fromParameters([]); + $xmlConfiguration = (new XmlConfigurationLoader)->load(__DIR__ . '/../../../../end-to-end/_files/groups/phpunit.xml'); + $configuration = (new ConfigurationMerger)->merge($cliConfiguration, $xmlConfiguration); + + return (new TestSuiteMapper)->map( + $configuration->configurationFile(), + $configuration->testSuite(), + $configuration->includeTestSuites(), + $configuration->excludeTestSuites(), + ); + } +} diff --git a/tests/unit/Event/Value/TestSuite/TestSuiteTest.php b/tests/unit/Event/Value/TestSuite/TestSuiteTest.php new file mode 100644 index 00000000000..3c780b13899 --- /dev/null +++ b/tests/unit/Event/Value/TestSuite/TestSuiteTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\TestSuite; + +use PHPUnit\Event\Code\TestCollection; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestSuite::class)] +#[CoversClassesThatExtendClass(TestSuite::class)] +#[Small] +final class TestSuiteTest extends TestCase +{ + public function testCanBeTestSuiteForTestClass(): void + { + $className = 'ExampleTest'; + $size = 0; + $tests = TestCollection::fromArray([]); + $file = 'ExampleTest.php'; + $line = 1; + + $testSuite = new TestSuiteForTestClass($className, $size, $tests, $file, $line); + + $this->assertTrue($testSuite->isForTestClass()); + $this->assertFalse($testSuite->isForTestMethodWithDataProvider()); + $this->assertFalse($testSuite->isWithName()); + + $this->assertSame($className, $testSuite->className()); + $this->assertSame($className, $testSuite->name()); + $this->assertSame($size, $testSuite->count()); + $this->assertSame($tests, $testSuite->tests()); + $this->assertSame($file, $testSuite->file()); + $this->assertSame($line, $testSuite->line()); + } + + public function testCanBeTestSuiteForTestMethodWithDataProvider(): void + { + $name = 'ExampleTest::testOne'; + $className = 'ExampleTest'; + $methodName = 'testOne'; + $size = 0; + $tests = TestCollection::fromArray([]); + $file = 'ExampleTest.php'; + $line = 1; + + $testSuite = new TestSuiteForTestMethodWithDataProvider($name, $size, $tests, $className, $methodName, $file, $line); + + $this->assertFalse($testSuite->isForTestClass()); + $this->assertTrue($testSuite->isForTestMethodWithDataProvider()); + $this->assertFalse($testSuite->isWithName()); + + $this->assertSame($name, $testSuite->name()); + $this->assertSame($className, $testSuite->className()); + $this->assertSame($methodName, $testSuite->methodName()); + $this->assertSame($size, $testSuite->count()); + $this->assertSame($tests, $testSuite->tests()); + $this->assertSame($file, $testSuite->file()); + $this->assertSame($line, $testSuite->line()); + } + + public function testCanBeTestSuiteWithName(): void + { + $name = 'the-name'; + $size = 0; + $tests = TestCollection::fromArray([]); + + $testSuite = new TestSuiteWithName($name, $size, $tests); + + $this->assertFalse($testSuite->isForTestClass()); + $this->assertFalse($testSuite->isForTestMethodWithDataProvider()); + $this->assertTrue($testSuite->isWithName()); + + $this->assertSame($name, $testSuite->name()); + $this->assertSame($size, $testSuite->count()); + $this->assertSame($tests, $testSuite->tests()); + } +} diff --git a/tests/unit/Event/Value/ThrowableTest.php b/tests/unit/Event/Value/ThrowableTest.php new file mode 100644 index 00000000000..3dc846331e6 --- /dev/null +++ b/tests/unit/Event/Value/ThrowableTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Event\Code; + +use Exception; +use PHPUnit\Event\NoPreviousThrowableException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\Filter; + +#[CoversClass(Throwable::class)] +#[CoversClass(ThrowableBuilder::class)] +#[Small] +final class ThrowableTest extends TestCase +{ + public function testCanBeCreatedForThrowableWithoutPrevious(): void + { + $e = new Exception('message', 123, null); + $t = ThrowableBuilder::from($e); + + $this->assertSame(Exception::class, $t->className()); + $this->assertSame('message', $t->message()); + $this->assertSame("Exception: message\n", $t->description()); + $this->assertSame(Filter::stackTraceFromThrowableAsString($e), $t->stackTrace()); + $this->assertFalse($t->hasPrevious()); + + $this->expectException(NoPreviousThrowableException::class); + + $t->previous(); + } + + public function testCanBeCreatedForThrowableWithPrevious(): void + { + $first = new Exception('first message', 123, null); + $second = new Exception('second message', 456, $first); + $t = ThrowableBuilder::from($second); + + $this->assertSame(Exception::class, $t->className()); + $this->assertSame('second message', $t->message()); + $this->assertSame("Exception: second message\n", $t->description()); + $this->assertSame(Filter::stackTraceFromThrowableAsString($second, false), $t->stackTrace()); + $this->assertTrue($t->hasPrevious()); + + $previous = $t->previous(); + + $this->assertSame(Exception::class, $previous->className()); + $this->assertSame('first message', $previous->message()); + $this->assertSame("Exception: first message\n", $previous->description()); + $this->assertSame(Filter::stackTraceFromThrowableAsString($first), $previous->stackTrace()); + + $this->assertStringMatchesFormat( + <<<'EOD' +Exception: second message + +%A +Caused by +Exception: first message + +%A +EOD + , + $t->asString(), + ); + } +} diff --git a/tests/unit/Framework/Assert/FunctionsTest.php b/tests/unit/Framework/Assert/FunctionsTest.php new file mode 100644 index 00000000000..247be881971 --- /dev/null +++ b/tests/unit/Framework/Assert/FunctionsTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function array_reduce; +use function file_get_contents; +use function preg_match_all; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversNothing] +#[TestDox('Global Assertion Functions')] +final class FunctionsTest extends TestCase +{ + private static array $globalAssertionFunctions = []; + + public static function provideStaticAssertionMethodNames(): array + { + preg_match_all( + '/public static function (assert[^ (]+)/', + file_get_contents( + __DIR__ . '/../../../../src/Framework/Assert.php', + ), + $matches, + ); + + return array_reduce( + $matches[1], + static function (array $functionNames, string $functionName) + { + $functionNames[$functionName] = [$functionName]; + + return $functionNames; + }, + [], + ); + } + + public static function setUpBeforeClass(): void + { + preg_match_all( + '/function (assert[^ (]+)/', + file_get_contents( + __DIR__ . '/../../../../src/Framework/Assert/Functions.php', + ), + $matches, + ); + + self::$globalAssertionFunctions = $matches[1]; + } + + #[DataProvider('provideStaticAssertionMethodNames')] + #[TestDox('PHPUnit\Framework\Assert::$methodName() is available as global function $methodName()')] + public function testGlobalFunctionsFileContainsAllStaticAssertions(string $methodName): void + { + Assert::assertContains( + $methodName, + self::$globalAssertionFunctions, + "Mapping for Assert::{$methodName} is missing in Functions.php", + ); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayHasKeyTest.php b/tests/unit/Framework/Assert/assertArrayHasKeyTest.php new file mode 100644 index 00000000000..82335a66fe6 --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayHasKeyTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use ArrayAccess; +use ArrayObject; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\TestFixture\SampleArrayAccess; + +#[CoversMethod(Assert::class, 'assertArrayHasKey')] +#[TestDox('assertArrayHasKey()')] +#[Small] +final class assertArrayHasKeyTest extends TestCase +{ + /** + * @return non-empty-list|ArrayAccess}> + */ + public static function successProvider(): array + { + $arrayAccess = new SampleArrayAccess; + $arrayAccess['foo'] = 'bar'; + + $arrayObject = new ArrayObject; + $arrayObject['foo'] = 'bar'; + + return [ + [0, ['foo']], + ['foo', ['foo' => 'bar']], + ['foo', $arrayAccess], + ['foo', $arrayObject], + ]; + } + + /** + * @return non-empty-list|ArrayAccess}> + */ + public static function failureProvider(): array + { + $arrayAccess = new SampleArrayAccess; + $arrayAccess['foo'] = 'bar'; + + $arrayObject = new ArrayObject; + $arrayObject['foo'] = 'bar'; + + return [ + [1, ['foo']], + ['bar', ['foo' => 'bar']], + ['bar', $arrayAccess], + ['bar', $arrayObject], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(int|string $key, array|ArrayAccess $array): void + { + $this->assertArrayHasKey($key, $array); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(int|string $key, array|ArrayAccess $array): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayHasKey($key, $array); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayIsEqualToArrayIgnoringListOfKeysTest.php b/tests/unit/Framework/Assert/assertArrayIsEqualToArrayIgnoringListOfKeysTest.php new file mode 100644 index 00000000000..54249358482 --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayIsEqualToArrayIgnoringListOfKeysTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertArrayIsEqualToArrayIgnoringListOfKeys')] +#[TestDox('assertArrayIsEqualToArrayIgnoringListOfKeys()')] +#[Small] +final class assertArrayIsEqualToArrayIgnoringListOfKeysTest extends TestCase +{ + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function successProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b', 1], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + [2.0], + ], + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + [0 => 1, 1 => 3, 'a' => 'b', 'b' => 'b'], + ['b', 1], + ], + ]; + } + + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function failureProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b'], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + ['1'], + ], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(array $expected, array $actual, array $keysToBeIgnored): void + { + $this->assertArrayIsEqualToArrayIgnoringListOfKeys($expected, $actual, $keysToBeIgnored); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(array $expected, array $actual, array $keysToBeIgnored): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayIsEqualToArrayIgnoringListOfKeys($expected, $actual, $keysToBeIgnored); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayIsEqualToArrayOnlyConsideringListOfKeysTest.php b/tests/unit/Framework/Assert/assertArrayIsEqualToArrayOnlyConsideringListOfKeysTest.php new file mode 100644 index 00000000000..bb33eef2514 --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayIsEqualToArrayOnlyConsideringListOfKeysTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertArrayIsEqualToArrayOnlyConsideringListOfKeys')] +#[TestDox('assertArrayIsEqualToArrayOnlyConsideringListOfKeys()')] +#[Small] +final class assertArrayIsEqualToArrayOnlyConsideringListOfKeysTest extends TestCase +{ + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function successProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['a', 0], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + [0, '1', '3.0'], + ], + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + [0 => 1, 1 => 3, 'a' => 'b', 'b' => 'b'], + ['a', 0], + ], + ]; + } + + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function failureProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b'], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + ['1', 2.0, '3.0'], + ], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(array $expected, array $actual, array $keysToBeConsidered): void + { + $this->assertArrayIsEqualToArrayOnlyConsideringListOfKeys($expected, $actual, $keysToBeConsidered); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(array $expected, array $actual, array $keysToBeConsidered): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayIsEqualToArrayOnlyConsideringListOfKeys($expected, $actual, $keysToBeConsidered); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayIgnoringListOfKeysTest.php b/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayIgnoringListOfKeysTest.php new file mode 100644 index 00000000000..d3701c7c952 --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayIgnoringListOfKeysTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertArrayIsIdenticalToArrayIgnoringListOfKeys')] +#[TestDox('assertArrayIsIdenticalToArrayIgnoringListOfKeys()')] +#[Small] +final class assertArrayIsIdenticalToArrayIgnoringListOfKeysTest extends TestCase +{ + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function successProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b', 1], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + [2.0], + ], + ]; + } + + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function failureProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b'], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + ['1'], + ], + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + [0 => 1, 1 => 3, 'a' => 'b', 'b' => 'b'], + ['b', 1], + ], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(array $expected, array $actual, array $keysToBeIgnored): void + { + $this->assertArrayIsIdenticalToArrayIgnoringListOfKeys($expected, $actual, $keysToBeIgnored); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(array $expected, array $actual, array $keysToBeIgnored): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayIsIdenticalToArrayIgnoringListOfKeys($expected, $actual, $keysToBeIgnored); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayOnlyConsideringListOfKeysTest.php b/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayOnlyConsideringListOfKeysTest.php new file mode 100644 index 00000000000..7dcdd5c64d5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayIsIdenticalToArrayOnlyConsideringListOfKeysTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys')] +#[TestDox('assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys()')] +#[Small] +final class assertArrayIsIdenticalToArrayOnlyConsideringListOfKeysTest extends TestCase +{ + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function successProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['a', 0], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + [0, '1', '3.0'], + ], + ]; + } + + /** + * @return non-empty-list, 1: array, 2: array}> + */ + public static function failureProvider(): array + { + return [ + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + ['a' => 'b', 'b' => 'b', 0 => 1, 1 => 3], + ['b'], + ], + [ + [0 => 1, '1' => 2, 2.0 => 3, '3.0' => 4], + [0 => 1, '1' => 2, 2.0 => 2, '3.0' => 4], + ['1', 2.0, '3.0'], + ], + [ + ['a' => 'b', 'b' => 'c', 0 => 1, 1 => 2], + [0 => 1, 1 => 3, 'a' => 'b', 'b' => 'b'], + ['a', 0], + ], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(array $expected, array $actual, array $keysToBeConsidered): void + { + $this->assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys($expected, $actual, $keysToBeConsidered); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(array $expected, array $actual, array $keysToBeConsidered): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayIsIdenticalToArrayOnlyConsideringListOfKeys($expected, $actual, $keysToBeConsidered); + } +} diff --git a/tests/unit/Framework/Assert/assertArrayNotHasKeyTest.php b/tests/unit/Framework/Assert/assertArrayNotHasKeyTest.php new file mode 100644 index 00000000000..983bc1948fc --- /dev/null +++ b/tests/unit/Framework/Assert/assertArrayNotHasKeyTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use ArrayAccess; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertArrayNotHasKey')] +#[TestDox('assertArrayNotHasKey()')] +#[Small] +final class assertArrayNotHasKeyTest extends TestCase +{ + #[DataProviderExternal(assertArrayHasKeyTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(int|string $key, array|ArrayAccess $array): void + { + $this->assertArrayNotHasKey($key, $array); + } + + #[DataProviderExternal(assertArrayHasKeyTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(int|string $key, array|ArrayAccess $array): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertArrayNotHasKey($key, $array); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsEqualsTest.php b/tests/unit/Framework/Assert/assertContainsEqualsTest.php new file mode 100644 index 00000000000..814fa70c342 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsEqualsTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertContainsEquals')] +#[TestDox('assertContainsEquals()')] +#[Small] +final class assertContainsEqualsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $a = new stdClass; + $a->foo = 'bar'; + + $b = new stdClass; + $b->foo = 'bar'; + + return [ + [0, [0]], + [0, ['0']], + [0, [0.0]], + [0, [false]], + [0, [null]], + ['string', ['string']], + [['string'], [['string']]], + [$a, [$b]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $a = new stdClass; + $a->foo = 'bar'; + + $b = new stdClass; + $b->foo = 'baz'; + + return [ + [1, [0]], + [1, [0.0]], + [1, [false]], + [1, [null]], + ['string', ['another-string']], + [['string'], [['another-string']]], + [$a, [$b]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $needle, iterable $haystack): void + { + $this->assertContainsEquals($needle, $haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $needle, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsEquals($needle, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyArrayTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyArrayTest.php new file mode 100644 index 00000000000..6bd29ce7cf4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyArrayTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyArray')] +#[TestDox('assertContainsNotOnlyArray()')] +#[Small] +final class assertContainsNotOnlyArrayTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyArrayTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyArray($haystack); + } + + #[DataProviderExternal(assertContainsOnlyArrayTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyArray($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyBoolTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyBoolTest.php new file mode 100644 index 00000000000..ad6ad8a079c --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyBoolTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyBool')] +#[TestDox('assertContainsNotOnlyBool()')] +#[Small] +final class assertContainsNotOnlyBoolTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyBoolTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyBool($haystack); + } + + #[DataProviderExternal(assertContainsOnlyBoolTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyBool($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyCallableTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyCallableTest.php new file mode 100644 index 00000000000..7fe565c385a --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyCallableTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyCallable')] +#[TestDox('assertContainsNotOnlyCallable()')] +#[Small] +final class assertContainsNotOnlyCallableTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyCallableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyCallable($haystack); + } + + #[DataProviderExternal(assertContainsOnlyCallableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyCallable($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyClosedResourceTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyClosedResourceTest.php new file mode 100644 index 00000000000..f4a503184be --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyClosedResourceTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyClosedResource')] +#[TestDox('assertContainsNotOnlyClosedResource()')] +#[Small] +final class assertContainsNotOnlyClosedResourceTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyClosedResourceTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyClosedResource($haystack); + } + + #[DataProviderExternal(assertContainsOnlyClosedResourceTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyClosedResource($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyFloatTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyFloatTest.php new file mode 100644 index 00000000000..7d49a99eea0 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyFloatTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyFloat')] +#[TestDox('assertContainsNotOnlyFloat()')] +#[Small] +final class assertContainsNotOnlyFloatTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyFloatTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyFloat($haystack); + } + + #[DataProviderExternal(assertContainsOnlyFloatTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyFloat($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyInstancesOfTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyInstancesOfTest.php new file mode 100644 index 00000000000..f466c8476fb --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyInstancesOfTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyInstancesOf')] +#[TestDox('assertContainsNotOnlyInstancesOf()')] +#[Small] +final class assertContainsNotOnlyInstancesOfTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyInstancesOfTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, iterable $haystack): void + { + $this->assertContainsNotOnlyInstancesOf($type, $haystack); + } + + #[DataProviderExternal(assertContainsOnlyInstancesOfTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyInstancesOf($type, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyIntTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyIntTest.php new file mode 100644 index 00000000000..c60b24c5e07 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyIntTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyInt')] +#[TestDox('assertContainsNotOnlyInt()')] +#[Small] +final class assertContainsNotOnlyIntTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyIntTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyInt($haystack); + } + + #[DataProviderExternal(assertContainsOnlyIntTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyInt($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyIterableTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyIterableTest.php new file mode 100644 index 00000000000..fad89055b1c --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyIterableTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyIterable')] +#[TestDox('assertContainsNotOnlyIterable()')] +#[Small] +final class assertContainsNotOnlyIterableTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyIterableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyIterable($haystack); + } + + #[DataProviderExternal(assertContainsOnlyIterableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyIterable($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyNullTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyNullTest.php new file mode 100644 index 00000000000..61ca652ce87 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyNullTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyNull')] +#[TestDox('assertContainsNotOnlyNull()')] +#[Small] +final class assertContainsNotOnlyNullTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyNullTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyNull($haystack); + } + + #[DataProviderExternal(assertContainsOnlyNullTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyNull($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyNumericTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyNumericTest.php new file mode 100644 index 00000000000..e4d302a58dd --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyNumericTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyNumeric')] +#[TestDox('assertContainsNotOnlyNumeric()')] +#[Small] +final class assertContainsNotOnlyNumericTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyNumericTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyNumeric($haystack); + } + + #[DataProviderExternal(assertContainsOnlyNumericTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyNumeric($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyObjectTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyObjectTest.php new file mode 100644 index 00000000000..6931f382686 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyObjectTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyObject')] +#[TestDox('assertContainsNotOnlyObject()')] +#[Small] +final class assertContainsNotOnlyObjectTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyObjectTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyObject($haystack); + } + + #[DataProviderExternal(assertContainsOnlyObjectTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyObject($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyResourceTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyResourceTest.php new file mode 100644 index 00000000000..075386d4c23 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyResourceTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyResource')] +#[TestDox('assertContainsNotOnlyResource()')] +#[Small] +final class assertContainsNotOnlyResourceTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyResourceTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyResource($haystack); + } + + #[DataProviderExternal(assertContainsOnlyResourceTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyResource($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyScalarTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyScalarTest.php new file mode 100644 index 00000000000..eb24151adc4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyScalarTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyScalar')] +#[TestDox('assertContainsNotOnlyScalar()')] +#[Small] +final class assertContainsNotOnlyScalarTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyScalarTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyScalar($haystack); + } + + #[DataProviderExternal(assertContainsOnlyScalarTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyScalar($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsNotOnlyStringTest.php b/tests/unit/Framework/Assert/assertContainsNotOnlyStringTest.php new file mode 100644 index 00000000000..771bf0b092e --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsNotOnlyStringTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsNotOnlyString')] +#[TestDox('assertContainsNotOnlyString()')] +#[Small] +final class assertContainsNotOnlyStringTest extends TestCase +{ + #[DataProviderExternal(assertContainsOnlyStringTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsNotOnlyString($haystack); + } + + #[DataProviderExternal(assertContainsOnlyStringTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsNotOnlyString($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyArrayTest.php b/tests/unit/Framework/Assert/assertContainsOnlyArrayTest.php new file mode 100644 index 00000000000..adb56c27fdd --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyArrayTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyArray')] +#[TestDox('assertContainsOnlyArray()')] +#[Small] +final class assertContainsOnlyArrayTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[[]]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyArray($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyArray($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyBoolTest.php b/tests/unit/Framework/Assert/assertContainsOnlyBoolTest.php new file mode 100644 index 00000000000..2ef525be2c1 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyBoolTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyBool')] +#[TestDox('assertContainsOnlyBool()')] +#[Small] +final class assertContainsOnlyBoolTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[true]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyBool($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyBool($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyCallableTest.php b/tests/unit/Framework/Assert/assertContainsOnlyCallableTest.php new file mode 100644 index 00000000000..0344fafbb26 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyCallableTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyCallable')] +#[TestDox('assertContainsOnlyCallable()')] +#[Small] +final class assertContainsOnlyCallableTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $callable = static function (): void + {}; + + return [ + [[$callable]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyCallable($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyCallable($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyClosedResourceTest.php b/tests/unit/Framework/Assert/assertContainsOnlyClosedResourceTest.php new file mode 100644 index 00000000000..2545d1997e2 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyClosedResourceTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyClosedResource')] +#[TestDox('assertContainsOnlyClosedResource()')] +#[Small] +final class assertContainsOnlyClosedResourceTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $resource = fopen(__FILE__, 'r'); + + fclose($resource); + + return [ + [[$resource]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyClosedResource($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyClosedResource($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyFloatTest.php b/tests/unit/Framework/Assert/assertContainsOnlyFloatTest.php new file mode 100644 index 00000000000..3c51bc740a5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyFloatTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyFloat')] +#[TestDox('assertContainsOnlyFloat()')] +#[Small] +final class assertContainsOnlyFloatTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[0.0]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyFloat($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyFloat($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyInstancesOfTest.php b/tests/unit/Framework/Assert/assertContainsOnlyInstancesOfTest.php new file mode 100644 index 00000000000..47a703aaf81 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyInstancesOfTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertContainsOnlyInstancesOf')] +#[TestDox('assertContainsOnlyInstancesOf()')] +#[Small] +final class assertContainsOnlyInstancesOfTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [stdClass::class, [new stdClass]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [stdClass::class, [null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, iterable $haystack): void + { + $this->assertContainsOnlyInstancesOf($type, $haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyInstancesOf($type, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyIntTest.php b/tests/unit/Framework/Assert/assertContainsOnlyIntTest.php new file mode 100644 index 00000000000..e433ffb9b74 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyIntTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyInt')] +#[TestDox('assertContainsOnlyInt()')] +#[Small] +final class assertContainsOnlyIntTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[0]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyInt($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyInt($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyIterableTest.php b/tests/unit/Framework/Assert/assertContainsOnlyIterableTest.php new file mode 100644 index 00000000000..d959e0210d8 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyIterableTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyIterable')] +#[TestDox('assertContainsOnlyIterable()')] +#[Small] +final class assertContainsOnlyIterableTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[[]]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyIterable($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyIterable($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyNullTest.php b/tests/unit/Framework/Assert/assertContainsOnlyNullTest.php new file mode 100644 index 00000000000..6ddcf346b71 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyNullTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyNull')] +#[TestDox('assertContainsOnlyNull()')] +#[Small] +final class assertContainsOnlyNullTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[null]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[true]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyNull($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyNull($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyNumericTest.php b/tests/unit/Framework/Assert/assertContainsOnlyNumericTest.php new file mode 100644 index 00000000000..85d90e006b9 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyNumericTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyNumeric')] +#[TestDox('assertContainsOnlyNumeric()')] +#[Small] +final class assertContainsOnlyNumericTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [['1.0']], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyNumeric($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyNumeric($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyObjectTest.php b/tests/unit/Framework/Assert/assertContainsOnlyObjectTest.php new file mode 100644 index 00000000000..875a033881a --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyObjectTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertContainsOnlyObject')] +#[TestDox('assertContainsOnlyObject()')] +#[Small] +final class assertContainsOnlyObjectTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[new stdClass]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyObject($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyObject($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyResourceTest.php b/tests/unit/Framework/Assert/assertContainsOnlyResourceTest.php new file mode 100644 index 00000000000..21ec16022e4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyResourceTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyResource')] +#[TestDox('assertContainsOnlyResource()')] +#[Small] +final class assertContainsOnlyResourceTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $resource = fopen(__FILE__, 'r'); + + return [ + [[$resource]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyResource($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyResource($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyScalarTest.php b/tests/unit/Framework/Assert/assertContainsOnlyScalarTest.php new file mode 100644 index 00000000000..c5275fc1af3 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyScalarTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyScalar')] +#[TestDox('assertContainsOnlyScalar()')] +#[Small] +final class assertContainsOnlyScalarTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [['string']], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyScalar($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyScalar($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsOnlyStringTest.php b/tests/unit/Framework/Assert/assertContainsOnlyStringTest.php new file mode 100644 index 00000000000..1ea75ddc544 --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsOnlyStringTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertContainsOnlyString')] +#[TestDox('assertContainsOnlyString()')] +#[Small] +final class assertContainsOnlyStringTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [['string']], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[null]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(iterable $haystack): void + { + $this->assertContainsOnlyString($haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContainsOnlyString($haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertContainsTest.php b/tests/unit/Framework/Assert/assertContainsTest.php new file mode 100644 index 00000000000..c471f00084b --- /dev/null +++ b/tests/unit/Framework/Assert/assertContainsTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertContains')] +#[TestDox('assertContains()')] +#[Small] +final class assertContainsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $a = new stdClass; + + return [ + [0, [0]], + [0.0, [0.0]], + [false, [false]], + [null, [null]], + ['string', ['string']], + [['string'], [['string']]], + [$a, [$a]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [0, ['0']], + [0, [0.0]], + [0, [false]], + [0, [null]], + [new stdClass, [new stdClass]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $needle, iterable $haystack): void + { + $this->assertContains($needle, $haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $needle, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertContains($needle, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertCountTest.php b/tests/unit/Framework/Assert/assertCountTest.php new file mode 100644 index 00000000000..ba1ab1cc847 --- /dev/null +++ b/tests/unit/Framework/Assert/assertCountTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function PHPUnit\TestFixture\Generator\f; +use ArrayIterator; +use Countable; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertCount')] +#[CoversClass(GeneratorNotSupportedException::class)] +#[TestDox('assertCount()')] +#[Small] +final class assertCountTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [2, [1, 2]], + [2, new ArrayIterator([1, 2])], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [2, [1, 2, 3]], + [2, new ArrayIterator([1, 2, 3])], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(int $expectedCount, Countable|iterable $haystack): void + { + $this->assertCount($expectedCount, $haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(int $expectedCount, Countable|iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertCount($expectedCount, $haystack); + } + + public function testDoesNotSupportGenerators(): void + { + $this->expectException(GeneratorNotSupportedException::class); + $this->expectExceptionMessage('Passing an argument of type Generator for the $haystack parameter is not supported'); + + $this->assertCount(0, f()); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryDoesNotExistTest.php b/tests/unit/Framework/Assert/assertDirectoryDoesNotExistTest.php new file mode 100644 index 00000000000..1248bbb65c2 --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryDoesNotExistTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryDoesNotExist')] +#[TestDox('assertDirectoryDoesNotExist()')] +#[Small] +final class assertDirectoryDoesNotExistTest extends TestCase +{ + #[DataProviderExternal(assertDirectoryExistsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $directory): void + { + $this->assertDirectoryDoesNotExist($directory); + } + + #[DataProviderExternal(assertDirectoryExistsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $directory): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryDoesNotExist($directory); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryExistsTest.php b/tests/unit/Framework/Assert/assertDirectoryExistsTest.php new file mode 100644 index 00000000000..9609f7b48fd --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryExistsTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryExists')] +#[TestDox('assertDirectoryExists()')] +#[Small] +final class assertDirectoryExistsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [__DIR__], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [__DIR__ . '/DoesNotExist'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $directory): void + { + $this->assertDirectoryExists($directory); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $directory): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryExists($directory); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryIsNotReadableTest.php b/tests/unit/Framework/Assert/assertDirectoryIsNotReadableTest.php new file mode 100644 index 00000000000..1a9a869480d --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryIsNotReadableTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function uniqid; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryIsNotReadable')] +#[TestDox('assertDirectoryIsNotReadable()')] +#[Small] +final class assertDirectoryIsNotReadableTest extends TestCase +{ + private string $directory; + + protected function setUp(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + $this->directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true); + } + + protected function tearDown(): void + { + if (!isset($this->directory)) { + return; + } + + @rmdir($this->directory); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + mkdir($this->directory, octdec('0')); + + $this->assertDirectoryIsNotReadable($this->directory); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryIsNotReadable(__DIR__); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryIsNotWritableTest.php b/tests/unit/Framework/Assert/assertDirectoryIsNotWritableTest.php new file mode 100644 index 00000000000..d7fd7de6a99 --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryIsNotWritableTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function uniqid; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryIsNotWritable')] +#[TestDox('assertDirectoryIsNotWritable()')] +#[Small] +final class assertDirectoryIsNotWritableTest extends TestCase +{ + private string $directory; + + protected function setUp(): void + { + $this->directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true); + } + + protected function tearDown(): void + { + @rmdir($this->directory); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + mkdir($this->directory, octdec('0')); + + $this->assertDirectoryIsNotWritable($this->directory); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryIsNotWritable(__DIR__); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryIsReadableTest.php b/tests/unit/Framework/Assert/assertDirectoryIsReadableTest.php new file mode 100644 index 00000000000..3e41b1146f2 --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryIsReadableTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function uniqid; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryIsReadable')] +#[TestDox('assertDirectoryIsReadable()')] +#[Small] +final class assertDirectoryIsReadableTest extends TestCase +{ + private string $directory; + + protected function setUp(): void + { + $this->directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true); + } + + protected function tearDown(): void + { + @rmdir($this->directory); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertDirectoryIsReadable(__DIR__); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + mkdir($this->directory, octdec('0')); + + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryIsReadable($this->directory); + } +} diff --git a/tests/unit/Framework/Assert/assertDirectoryIsWritableTest.php b/tests/unit/Framework/Assert/assertDirectoryIsWritableTest.php new file mode 100644 index 00000000000..9043913b132 --- /dev/null +++ b/tests/unit/Framework/Assert/assertDirectoryIsWritableTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function uniqid; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDirectoryIsWritable')] +#[TestDox('assertDirectoryIsWritable()')] +#[Small] +final class assertDirectoryIsWritableTest extends TestCase +{ + private string $directory; + + protected function setUp(): void + { + $this->directory = sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true); + } + + protected function tearDown(): void + { + @rmdir($this->directory); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertDirectoryIsWritable(__DIR__); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + mkdir($this->directory, octdec('0')); + + $this->expectException(AssertionFailedError::class); + + $this->assertDirectoryIsWritable($this->directory); + } +} diff --git a/tests/unit/Framework/Assert/assertDoesNotMatchRegularExpressionTest.php b/tests/unit/Framework/Assert/assertDoesNotMatchRegularExpressionTest.php new file mode 100644 index 00000000000..953facdba90 --- /dev/null +++ b/tests/unit/Framework/Assert/assertDoesNotMatchRegularExpressionTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertDoesNotMatchRegularExpression')] +#[TestDox('assertDoesNotMatchRegularExpression()')] +#[Small] +final class assertDoesNotMatchRegularExpressionTest extends TestCase +{ + #[DataProviderExternal(assertMatchesRegularExpressionTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $pattern, string $string): void + { + $this->assertDoesNotMatchRegularExpression($pattern, $string); + } + + #[DataProviderExternal(assertMatchesRegularExpressionTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $pattern, string $string): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertDoesNotMatchRegularExpression($pattern, $string); + } +} diff --git a/tests/unit/Framework/Assert/assertEmptyTest.php b/tests/unit/Framework/Assert/assertEmptyTest.php new file mode 100644 index 00000000000..f90fdf27b84 --- /dev/null +++ b/tests/unit/Framework/Assert/assertEmptyTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function PHPUnit\TestFixture\Generator\f; +use Countable; +use EmptyIterator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertEmpty')] +#[CoversClass(GeneratorNotSupportedException::class)] +#[TestDox('assertEmpty()')] +#[Small] +final class assertEmptyTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[]], + [''], + [null], + [false], + ['0'], + [0], + [new EmptyIterator], + [ + new class implements Countable + { + public function count(): int + { + return 0; + } + }, + ], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[0]], + [true], + ['1'], + [ + new class implements Countable + { + public function count(): int + { + return 1; + } + }, + ], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertEmpty($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertEmpty($actual); + } + + public function testDoesNotSupportGenerators(): void + { + $this->expectException(GeneratorNotSupportedException::class); + $this->expectExceptionMessage('Passing an argument of type Generator for the $actual parameter is not supported'); + + $this->assertEmpty(f()); + } +} diff --git a/tests/unit/Framework/Assert/assertEqualsCanonicalizingTest.php b/tests/unit/Framework/Assert/assertEqualsCanonicalizingTest.php new file mode 100644 index 00000000000..6d6268b146d --- /dev/null +++ b/tests/unit/Framework/Assert/assertEqualsCanonicalizingTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertEqualsCanonicalizing')] +#[TestDox('assertEqualsCanonicalizing()')] +#[Small] +final class assertEqualsCanonicalizingTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[3, 2, 1], [2, 3, 1]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[3, 2, 1], [2, 3, 4]], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertEqualsCanonicalizing($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertEqualsCanonicalizing($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertEqualsIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertEqualsIgnoringCaseTest.php new file mode 100644 index 00000000000..6809fa5e64c --- /dev/null +++ b/tests/unit/Framework/Assert/assertEqualsIgnoringCaseTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertEqualsIgnoringCase')] +#[TestDox('assertEqualsIgnoringCase()')] +#[Small] +final class assertEqualsIgnoringCaseTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['a', 'A'], + [['a'], ['A']], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['a', 'B'], + [['a'], ['B']], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertEqualsIgnoringCase($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertEqualsIgnoringCase($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertEqualsTest.php b/tests/unit/Framework/Assert/assertEqualsTest.php new file mode 100644 index 00000000000..d6ba5d660ab --- /dev/null +++ b/tests/unit/Framework/Assert/assertEqualsTest.php @@ -0,0 +1,300 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const NAN; +use function acos; +use function array_merge; +use function fopen; +use DateTimeImmutable; +use DateTimeZone; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\TestFixture\Author; +use PHPUnit\TestFixture\Book; +use PHPUnit\TestFixture\ClassWithToString; +use PHPUnit\TestFixture\SampleClass; +use PHPUnit\TestFixture\Struct; +use PHPUnit\Util\Xml\Loader as XmlLoader; +use SplObjectStorage; +use stdClass; + +#[CoversMethod(Assert::class, 'assertEquals')] +#[TestDox('assertEquals()')] +#[Small] +final class assertEqualsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return array_merge(self::equalValues(), assertSameTest::sameValues()); + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return self::notEqualValues(); + } + + /** + * @return non-empty-list + */ + public static function equalValues(): array + { + // cyclic dependencies + $book1 = new Book; + $book1->author = new Author('Terry Pratchett'); + $book1->author->books[] = $book1; + $book2 = new Book; + $book2->author = new Author('Terry Pratchett'); + $book2->author->books[] = $book2; + + $object1 = new SampleClass(4, 8, 15); + $object2 = new SampleClass(4, 8, 15); + $storage1 = new SplObjectStorage; + $storage1->offsetSet($object1); + $storage2 = new SplObjectStorage; + $storage2->offsetSet($object1); + + return [ + // arrays + [['a' => 1, 'b' => 2], ['b' => 2, 'a' => 1]], + [[1], ['1']], + // objects + [$object1, $object2], + [$book1, $book2], + // SplObjectStorage + [$storage1, $storage2], + // DOMDocument + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load("\n \n"), + (new XmlLoader)->load(''), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 03:13:35', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('2013-03-30', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 23:00:00', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('@1364616000'), + new DateTimeImmutable('2013-03-29 23:00:00', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('2013-03-29T05:13:35-0500'), + new DateTimeImmutable('2013-03-29T04:13:35-0600'), + ], + // Exception + // array(new Exception('Exception 1'), new Exception('Exception 1')), + // mixed types + [0, '0'], + ['0', 0], + [2.3, '2.3'], + ['2.3', 2.3], + [1, 1.0], + [1.0, '1'], + [1 / 3, '0.3333333333333333'], + [1 - 2 / 3, '0.33333333333333337'], + [5.5E+123, '5.5E+123'], + [5.5E-123, '5.5E-123'], + ['string representation', new ClassWithToString], + [new ClassWithToString, 'string representation'], + ]; + } + + /** + * @return non-empty-list + */ + public static function notEqualValues(): array + { + // cyclic dependencies + $book1 = new Book; + $book1->author = new Author('Terry Pratchett'); + $book1->author->books[] = $book1; + $book2 = new Book; + $book2->author = new Author('Terry Pratch'); + $book2->author->books[] = $book2; + + $book3 = new Book; + $book3->author = 'Terry Pratchett'; + $book4 = new stdClass; + $book4->author = 'Terry Pratchett'; + + $object1 = new SampleClass(4, 8, 15); + $object2 = new SampleClass(16, 23, 42); + $object3 = new SampleClass(4, 8, 15); + $storage1 = new SplObjectStorage; + $storage1->offsetSet($object1); + $storage2 = new SplObjectStorage; + $storage2->offsetSet($object3); // same content, different object + + $file = TEST_FILES_PATH . 'foo.xml'; + + return [ + [true, false], + // strings + ['a', 'b'], + ['a', 'A'], + // https://github.com/sebastianbergmann/phpunit/issues/1023 + ['9E6666666', '9E7777777'], + // integers + [1, 2], + [2, 1], + // floats + [2.3, 4.2], + [2.3, 4.2], + [[2.3], [4.2]], + [[[2.3]], [[4.2]]], + [new Struct(2.3), new Struct(4.2)], + [[new Struct(2.3)], [new Struct(4.2)]], + [1 / 3, 1 - 2 / 3], + [1 / 3, '0.33333333333333337'], + [1 - 2 / 3, '3333333333333333'], + [5.5E+123, 5.6E+123], + [5.5E-123, 5.6E-123], + [5.5E+123, 5.5E-123], + // NAN + [NAN, NAN], + // arrays + [[], [0 => 1]], + [[0 => 1], []], + [[0 => null], []], + [[0 => 1, 1 => 2], [0 => 1, 1 => 3]], + [['a', 'b' => [1, 2]], ['a', 'b' => [2, 1]]], + // objects + [new SampleClass(4, 8, 15), new SampleClass(16, 23, 42)], + [$object1, $object2], + [$book1, $book2], + [$book3, $book4], // same content, different class + // resources + [fopen($file, 'r'), fopen($file, 'r')], + // SplObjectStorage + [$storage1, $storage2], + // DOMDocument + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(' bar '), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(''), + (new XmlLoader)->load(''), + ], + [ + (new XmlLoader)->load(' bar '), + (new XmlLoader)->load(' bir '), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 03:13:35', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 03:13:35', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 05:13:35', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-30', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-30', new DateTimeZone('America/New_York')), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-29 04:13:35', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('2013-03-30', new DateTimeZone('America/New_York')), + new DateTimeImmutable('2013-03-30', new DateTimeZone('America/Chicago')), + ], + [ + new DateTimeImmutable('2013-03-29T05:13:35-0600'), + new DateTimeImmutable('2013-03-29T04:13:35-0600'), + ], + [ + new DateTimeImmutable('2013-03-29T05:13:35-0600'), + new DateTimeImmutable('2013-03-29T05:13:35-0500'), + ], + // Exception + // array(new Exception('Exception 1'), new Exception('Exception 2')), + // different types + [new SampleClass(4, 8, 15), false], + [false, new SampleClass(4, 8, 15)], + [[0 => 1, 1 => 2], false], + [false, [0 => 1, 1 => 2]], + [[], new stdClass], + [new stdClass, []], + // PHP: 0 == 'Foobar' => true! + // We want these values to differ + [0, 'Foobar'], + ['Foobar', 0], + [3, acos(8)], + [acos(8), 3], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertEquals($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertEquals($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertEqualsWithDeltaTest.php b/tests/unit/Framework/Assert/assertEqualsWithDeltaTest.php new file mode 100644 index 00000000000..93efad122c0 --- /dev/null +++ b/tests/unit/Framework/Assert/assertEqualsWithDeltaTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertEqualsWithDelta')] +#[TestDox('assertEqualsWithDelta()')] +#[Small] +final class assertEqualsWithDeltaTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [2.3, 2.5, 0.5], + [[2.3], [2.5], 0.5], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [2.3, 3.5, 0.5], + [[2.3], [3.5], 0.5], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual, float $delta): void + { + $this->assertEqualsWithDelta($expected, $actual, $delta); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual, float $delta): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertEqualsWithDelta($expected, $actual, $delta); + } +} diff --git a/tests/unit/Framework/Assert/assertFalseTest.php b/tests/unit/Framework/Assert/assertFalseTest.php new file mode 100644 index 00000000000..caea5451d7b --- /dev/null +++ b/tests/unit/Framework/Assert/assertFalseTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFalse')] +#[TestDox('assertFalse()')] +#[Small] +final class assertFalseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFalse(false); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFalse(true); + } +} diff --git a/tests/unit/Framework/Assert/assertFileDoesNotExistTest.php b/tests/unit/Framework/Assert/assertFileDoesNotExistTest.php new file mode 100644 index 00000000000..146bcd753e7 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileDoesNotExistTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileDoesNotExist')] +#[TestDox('assertFileDoesNotExist()')] +#[Small] +final class assertFileDoesNotExistTest extends TestCase +{ + #[DataProviderExternal(assertFileExistsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $directory): void + { + $this->assertFileDoesNotExist($directory); + } + + #[DataProviderExternal(assertFileExistsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $directory): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileDoesNotExist($directory); + } +} diff --git a/tests/unit/Framework/Assert/assertFileEqualsCanonicalizingTest.php b/tests/unit/Framework/Assert/assertFileEqualsCanonicalizingTest.php new file mode 100644 index 00000000000..64100d31c13 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileEqualsCanonicalizingTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileEqualsCanonicalizing')] +#[TestDox('assertFileEqualsCanonicalizing()')] +#[Small] +final class assertFileEqualsCanonicalizingTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileNotEquals(TEST_FILES_PATH . 'foo.txt', TEST_FILES_PATH . 'bar.txt'); + $this->assertFileEqualsCanonicalizing(TEST_FILES_PATH . 'foo.txt', TEST_FILES_PATH . 'foo.txt'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileEqualsCanonicalizing(TEST_FILES_PATH . 'foo.txt', TEST_FILES_PATH . 'foo.xml'); + } +} diff --git a/tests/unit/Framework/Assert/assertFileEqualsIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertFileEqualsIgnoringCaseTest.php new file mode 100644 index 00000000000..462914254de --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileEqualsIgnoringCaseTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileEqualsIgnoringCase')] +#[TestDox('assertFileEqualsIgnoringCase()')] +#[Small] +final class assertFileEqualsIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileEqualsIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'fooUppercase.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileEqualsIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFileEqualsTest.php b/tests/unit/Framework/Assert/assertFileEqualsTest.php new file mode 100644 index 00000000000..2e1d3c36750 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileEqualsTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileEquals')] +#[TestDox('assertFileEquals()')] +#[Small] +final class assertFileEqualsTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileEquals( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'foo.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileEquals( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFileExistsTest.php b/tests/unit/Framework/Assert/assertFileExistsTest.php new file mode 100644 index 00000000000..17c67fb501b --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileExistsTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileExists')] +#[TestDox('assertFileExists()')] +#[Small] +final class assertFileExistsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [__FILE__], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [__DIR__ . '/DoesNotExist'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $filename): void + { + $this->assertFileExists($filename); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $filename): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileExists($filename); + } +} diff --git a/tests/unit/Framework/Assert/assertFileIsNotReadableTest.php b/tests/unit/Framework/Assert/assertFileIsNotReadableTest.php new file mode 100644 index 00000000000..4454b7aa3cc --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileIsNotReadableTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function octdec; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileIsNotReadable')] +#[TestDox('assertFileIsNotReadable()')] +#[Small] +final class assertFileIsNotReadableTest extends TestCase +{ + private string $file; + + protected function setUp(): void + { + $this->file = tempnam(sys_get_temp_dir(), __CLASS__); + } + + protected function tearDown(): void + { + @unlink($this->file); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + chmod($this->file, octdec('0')); + + $this->assertFileIsNotReadable($this->file); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileIsNotReadable(__FILE__); + } +} diff --git a/tests/unit/Framework/Assert/assertFileIsNotWritableTest.php b/tests/unit/Framework/Assert/assertFileIsNotWritableTest.php new file mode 100644 index 00000000000..06977fd1e55 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileIsNotWritableTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function octdec; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileIsNotWritable')] +#[TestDox('assertFileIsNotWritable()')] +#[Small] +final class assertFileIsNotWritableTest extends TestCase +{ + private string $file; + + protected function setUp(): void + { + $this->file = tempnam(sys_get_temp_dir(), __CLASS__); + } + + protected function tearDown(): void + { + @unlink($this->file); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + chmod($this->file, octdec('0')); + + $this->assertFileIsNotWritable($this->file); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileIsNotWritable(__FILE__); + } +} diff --git a/tests/unit/Framework/Assert/assertFileIsReadableTest.php b/tests/unit/Framework/Assert/assertFileIsReadableTest.php new file mode 100644 index 00000000000..c01fae58a40 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileIsReadableTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function octdec; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileIsReadable')] +#[TestDox('assertFileIsReadable()')] +#[Small] +final class assertFileIsReadableTest extends TestCase +{ + private string $file; + + protected function setUp(): void + { + $this->file = tempnam(sys_get_temp_dir(), __CLASS__); + } + + protected function tearDown(): void + { + @unlink($this->file); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileIsReadable(__FILE__); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + chmod($this->file, octdec('0')); + + $this->expectException(AssertionFailedError::class); + + $this->assertFileIsReadable($this->file); + } +} diff --git a/tests/unit/Framework/Assert/assertFileIsWritableTest.php b/tests/unit/Framework/Assert/assertFileIsWritableTest.php new file mode 100644 index 00000000000..57bf35b75b4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileIsWritableTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function octdec; +use function sys_get_temp_dir; +use function tempnam; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileIsWritable')] +#[TestDox('assertFileIsWritable()')] +#[Small] +final class assertFileIsWritableTest extends TestCase +{ + private string $file; + + protected function setUp(): void + { + $this->file = tempnam(sys_get_temp_dir(), __CLASS__); + } + + protected function tearDown(): void + { + @unlink($this->file); + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileIsWritable(__FILE__); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + chmod($this->file, octdec('0')); + + $this->expectException(AssertionFailedError::class); + + $this->assertFileIsWritable($this->file); + } +} diff --git a/tests/unit/Framework/Assert/assertFileMatchesFormatFileTest.php b/tests/unit/Framework/Assert/assertFileMatchesFormatFileTest.php new file mode 100644 index 00000000000..d071bcc187d --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileMatchesFormatFileTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileMatchesFormatFile')] +#[TestDox('assertFileMatchesFormatFile()')] +#[Small] +final class assertFileMatchesFormatFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileMatchesFormatFile( + TEST_FILES_PATH . 'expectedFileFormat.txt', + TEST_FILES_PATH . 'expectedFileFormat.txt', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileMatchesFormatFile( + TEST_FILES_PATH . 'expectedFileFormat.txt', + TEST_FILES_PATH . 'actualFileFormat.txt', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFileMatchesFormatTest.php b/tests/unit/Framework/Assert/assertFileMatchesFormatTest.php new file mode 100644 index 00000000000..a92aeddb02b --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileMatchesFormatTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileMatchesFormat')] +#[TestDox('assertFileMatchesFormat()')] +#[Small] +final class assertFileMatchesFormatTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileMatchesFormat("FOO\n", TEST_FILES_PATH . 'expectedFileFormat.txt'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileMatchesFormat("BAR\n", TEST_FILES_PATH . 'expectedFileFormat.txt'); + } +} diff --git a/tests/unit/Framework/Assert/assertFileNotEqualsCanonicalizingTest.php b/tests/unit/Framework/Assert/assertFileNotEqualsCanonicalizingTest.php new file mode 100644 index 00000000000..4c93eb9e3a5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileNotEqualsCanonicalizingTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileNotEqualsCanonicalizing')] +#[TestDox('assertFileNotEqualsCanonicalizing()')] +#[Small] +final class assertFileNotEqualsCanonicalizingTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileNotEqualsCanonicalizing( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileNotEqualsCanonicalizing( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'foo.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFileNotEqualsIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertFileNotEqualsIgnoringCaseTest.php new file mode 100644 index 00000000000..84290d35eb9 --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileNotEqualsIgnoringCaseTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileNotEqualsIgnoringCase')] +#[TestDox('assertFileNotEqualsIgnoringCase()')] +#[Small] +final class assertFileNotEqualsIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileNotEqualsIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileNotEqualsIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'fooUppercase.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFileNotEqualsTest.php b/tests/unit/Framework/Assert/assertFileNotEqualsTest.php new file mode 100644 index 00000000000..d56d641a84a --- /dev/null +++ b/tests/unit/Framework/Assert/assertFileNotEqualsTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFileNotEquals')] +#[TestDox('assertFileNotEquals()')] +#[Small] +final class assertFileNotEqualsTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFileNotEquals( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFileNotEquals( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'foo.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertFiniteTest.php b/tests/unit/Framework/Assert/assertFiniteTest.php new file mode 100644 index 00000000000..cce2db0fd5c --- /dev/null +++ b/tests/unit/Framework/Assert/assertFiniteTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const INF; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertFinite')] +#[TestDox('assertFinite()')] +#[Small] +final class assertFiniteTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertFinite(1); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertFinite(INF); + } +} diff --git a/tests/unit/Framework/Assert/assertGreaterThanOrEqualTest.php b/tests/unit/Framework/Assert/assertGreaterThanOrEqualTest.php new file mode 100644 index 00000000000..5eddd82f285 --- /dev/null +++ b/tests/unit/Framework/Assert/assertGreaterThanOrEqualTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertGreaterThanOrEqual')] +#[TestDox('assertGreaterThanOrEqual()')] +#[Small] +final class assertGreaterThanOrEqualTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertGreaterThanOrEqual(1, 2); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertGreaterThanOrEqual(2, 1); + } +} diff --git a/tests/unit/Framework/Assert/assertGreaterThanTest.php b/tests/unit/Framework/Assert/assertGreaterThanTest.php new file mode 100644 index 00000000000..b043e57883e --- /dev/null +++ b/tests/unit/Framework/Assert/assertGreaterThanTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertGreaterThan')] +#[TestDox('assertGreaterThan()')] +#[Small] +final class assertGreaterThanTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertGreaterThan(1, 2); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertGreaterThan(2, 1); + } +} diff --git a/tests/unit/Framework/Assert/assertInfiniteTest.php b/tests/unit/Framework/Assert/assertInfiniteTest.php new file mode 100644 index 00000000000..b96f99d83a6 --- /dev/null +++ b/tests/unit/Framework/Assert/assertInfiniteTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const INF; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertInfinite')] +#[TestDox('assertInfinite()')] +#[Small] +final class assertInfiniteTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertInfinite(INF); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertInfinite(1); + } +} diff --git a/tests/unit/Framework/Assert/assertInstanceOfTest.php b/tests/unit/Framework/Assert/assertInstanceOfTest.php new file mode 100644 index 00000000000..e48cc7a135e --- /dev/null +++ b/tests/unit/Framework/Assert/assertInstanceOfTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertInstanceOf')] +#[CoversClass(UnknownClassOrInterfaceException::class)] +#[TestDox('assertInstanceOf()')] +#[Small] +final class assertInstanceOfTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [stdClass::class, new stdClass], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [self::class, new stdClass], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expected, mixed $actual): void + { + $this->assertInstanceOf($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertInstanceOf($expected, $actual); + } + + public function testDoesNotSupportUnknownTypes(): void + { + $this->expectException(UnknownClassOrInterfaceException::class); + $this->expectExceptionMessage('Class or interface "does-not-exist" does not exist'); + + $this->assertInstanceOf('does-not-exist', new stdClass); + } +} diff --git a/tests/unit/Framework/Assert/assertIsArrayTest.php b/tests/unit/Framework/Assert/assertIsArrayTest.php new file mode 100644 index 00000000000..8965b76ed07 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsArrayTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsArray')] +#[TestDox('assertIsArray()')] +#[Small] +final class assertIsArrayTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsArray([]); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsArray($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsBoolTest.php b/tests/unit/Framework/Assert/assertIsBoolTest.php new file mode 100644 index 00000000000..d68f0918782 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsBoolTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsBool')] +#[TestDox('assertIsBool()')] +#[Small] +final class assertIsBoolTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [true], + [false], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsBool($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsBool($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsCallableTest.php b/tests/unit/Framework/Assert/assertIsCallableTest.php new file mode 100644 index 00000000000..1d83cd06898 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsCallableTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsCallable')] +#[TestDox('assertIsCallable()')] +#[Small] +final class assertIsCallableTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [ + static function (): void + { + }, + ], + ['PHPUnit\Framework\assertIsCallable'], + [[Assert::class, 'assertIsCallable']], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsCallable($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsCallable($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsClosedResourceTest.php b/tests/unit/Framework/Assert/assertIsClosedResourceTest.php new file mode 100644 index 00000000000..b3554a2751f --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsClosedResourceTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsClosedResource')] +#[TestDox('assertIsClosedResource()')] +#[Small] +final class assertIsClosedResourceTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + return [ + [[]], + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + $this->assertIsClosedResource($closedResource); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsClosedResource($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsFloatTest.php b/tests/unit/Framework/Assert/assertIsFloatTest.php new file mode 100644 index 00000000000..d6ba3e3094d --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsFloatTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsFloat')] +#[TestDox('assertIsFloat()')] +#[Small] +final class assertIsFloatTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsFloat(0.0); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsFloat($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsIntTest.php b/tests/unit/Framework/Assert/assertIsIntTest.php new file mode 100644 index 00000000000..ef4978e4698 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsIntTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsInt')] +#[TestDox('assertIsInt()')] +#[Small] +final class assertIsIntTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [0.0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsInt(123); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsInt($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsIterableTest.php b/tests/unit/Framework/Assert/assertIsIterableTest.php new file mode 100644 index 00000000000..73374c8b496 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsIterableTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use ArrayIterator; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsIterable')] +#[TestDox('assertIsIterable()')] +#[Small] +final class assertIsIterableTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[]], + [new ArrayIterator([])], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsIterable($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsIterable($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsListTest.php b/tests/unit/Framework/Assert/assertIsListTest.php new file mode 100644 index 00000000000..1773154b5d9 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsListTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsList')] +#[TestDox('assertIsList()')] +#[Small] +final class assertIsListTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [['foo' => 'bar']], + [[1 => 'bar', 4 => 'baz']], + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsList([1, 2, 3]); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsList($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotArrayTest.php b/tests/unit/Framework/Assert/assertIsNotArrayTest.php new file mode 100644 index 00000000000..d1c7fcd9074 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotArrayTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotArray')] +#[TestDox('assertIsNotArray()')] +#[Small] +final class assertIsNotArrayTest extends TestCase +{ + #[DataProviderExternal(assertIsArrayTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotArray($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotArray([]); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotBoolTest.php b/tests/unit/Framework/Assert/assertIsNotBoolTest.php new file mode 100644 index 00000000000..eab1d98e309 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotBoolTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotBool')] +#[TestDox('assertIsNotBool()')] +#[Small] +final class assertIsNotBoolTest extends TestCase +{ + #[DataProviderExternal(assertIsBoolTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotBool($actual); + } + + #[DataProviderExternal(assertIsBoolTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotBool($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotCallableTest.php b/tests/unit/Framework/Assert/assertIsNotCallableTest.php new file mode 100644 index 00000000000..718a8593592 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotCallableTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotCallable')] +#[TestDox('assertIsNotCallable()')] +#[Small] +final class assertIsNotCallableTest extends TestCase +{ + #[DataProviderExternal(assertIsCallableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotCallable($actual); + } + + #[DataProviderExternal(assertIsCallableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotCallable($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotClosedResourceTest.php b/tests/unit/Framework/Assert/assertIsNotClosedResourceTest.php new file mode 100644 index 00000000000..d49115aaf95 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotClosedResourceTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotClosedResource')] +#[TestDox('assertIsNotClosedResource()')] +#[Small] +final class assertIsNotClosedResourceTest extends TestCase +{ + #[DataProviderExternal(assertIsClosedResourceTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotClosedResource($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotClosedResource($closedResource); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotFloatTest.php b/tests/unit/Framework/Assert/assertIsNotFloatTest.php new file mode 100644 index 00000000000..1735512edab --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotFloatTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotFloat')] +#[TestDox('assertIsNotFloat()')] +#[Small] +final class assertIsNotFloatTest extends TestCase +{ + #[DataProviderExternal(assertIsFloatTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotFloat($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotFloat(0.0); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotIntTest.php b/tests/unit/Framework/Assert/assertIsNotIntTest.php new file mode 100644 index 00000000000..3352a5aa5fb --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotIntTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotInt')] +#[TestDox('assertIsNotInt()')] +#[Small] +final class assertIsNotIntTest extends TestCase +{ + #[DataProviderExternal(assertIsIntTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotInt($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotInt(0); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotIterableTest.php b/tests/unit/Framework/Assert/assertIsNotIterableTest.php new file mode 100644 index 00000000000..8b5beafeaef --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotIterableTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotIterable')] +#[TestDox('assertIsNotIterable()')] +#[Small] +final class assertIsNotIterableTest extends TestCase +{ + #[DataProviderExternal(assertIsIterableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotIterable($actual); + } + + #[DataProviderExternal(assertIsIterableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotIterable($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotNumericTest.php b/tests/unit/Framework/Assert/assertIsNotNumericTest.php new file mode 100644 index 00000000000..f4ef42f4a43 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotNumericTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotNumeric')] +#[TestDox('assertIsNotNumeric()')] +#[Small] +final class assertIsNotNumericTest extends TestCase +{ + #[DataProviderExternal(assertIsNumericTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotNumeric($actual); + } + + #[DataProviderExternal(assertIsNumericTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotNumeric($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotObjectTest.php b/tests/unit/Framework/Assert/assertIsNotObjectTest.php new file mode 100644 index 00000000000..5684723311c --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotObjectTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsNotObject')] +#[TestDox('assertIsNotObject()')] +#[Small] +final class assertIsNotObjectTest extends TestCase +{ + #[DataProviderExternal(assertIsObjectTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotObject($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotObject(new stdClass); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotReadableTest.php b/tests/unit/Framework/Assert/assertIsNotReadableTest.php new file mode 100644 index 00000000000..effc8d6fd5c --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotReadableTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function mkdir; +use function octdec; +use function rmdir; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotReadable')] +#[TestDox('assertIsNotReadable()')] +#[Small] +final class assertIsNotReadableTest extends TestCase +{ + private ?string $directory = null; + private ?string $file = null; + + protected function tearDown(): void + { + if ($this->directory !== null) { + rmdir($this->directory); + } + + if ($this->file !== null) { + unlink($this->file); + } + } + + #[DataProviderExternal(assertIsReadableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, string $path): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + if ($type === 'directory') { + mkdir($path, octdec('0')); + + $this->directory = $path; + } else { + chmod($path, octdec('0')); + + $this->file = $path; + } + + $this->assertIsNotReadable($path); + } + + #[DataProviderExternal(assertIsReadableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, string $path): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotReadable($path); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotResourceTest.php b/tests/unit/Framework/Assert/assertIsNotResourceTest.php new file mode 100644 index 00000000000..b25b4b8a5f3 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotResourceTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotResource')] +#[TestDox('assertIsNotResource()')] +#[Small] +final class assertIsNotResourceTest extends TestCase +{ + #[DataProviderExternal(assertIsResourceTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotResource($actual); + } + + #[DataProviderExternal(assertIsResourceTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotResource($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotScalarTest.php b/tests/unit/Framework/Assert/assertIsNotScalarTest.php new file mode 100644 index 00000000000..0a6e621e6a7 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotScalarTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotScalar')] +#[TestDox('assertIsNotScalar()')] +#[Small] +final class assertIsNotScalarTest extends TestCase +{ + #[DataProviderExternal(assertIsScalarTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotScalar($actual); + } + + #[DataProviderExternal(assertIsScalarTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotScalar($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotStringTest.php b/tests/unit/Framework/Assert/assertIsNotStringTest.php new file mode 100644 index 00000000000..5a457a7ec0a --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotStringTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotString')] +#[TestDox('assertIsNotString()')] +#[Small] +final class assertIsNotStringTest extends TestCase +{ + #[DataProviderExternal(assertIsStringTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNotString($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotString('string'); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNotWritableTest.php b/tests/unit/Framework/Assert/assertIsNotWritableTest.php new file mode 100644 index 00000000000..ddb2ed508a5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNotWritableTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const PHP_OS_FAMILY; +use function chmod; +use function mkdir; +use function octdec; +use function rmdir; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsNotWritable')] +#[TestDox('assertIsNotWritable()')] +#[Small] +final class assertIsNotWritableTest extends TestCase +{ + private ?string $directory = null; + private ?string $file = null; + + protected function tearDown(): void + { + if ($this->directory !== null) { + rmdir($this->directory); + } + + if ($this->file !== null) { + unlink($this->file); + } + } + + #[DataProviderExternal(assertIsWritableTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, string $path): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + if ($type === 'directory') { + mkdir($path, octdec('0')); + + $this->directory = $path; + } else { + chmod($path, octdec('0')); + + $this->file = $path; + } + + $this->assertIsNotWritable($path); + } + + #[DataProviderExternal(assertIsWritableTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, string $path): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNotWritable($path); + } +} diff --git a/tests/unit/Framework/Assert/assertIsNumericTest.php b/tests/unit/Framework/Assert/assertIsNumericTest.php new file mode 100644 index 00000000000..5ff666a3d2f --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsNumericTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsNumeric')] +#[TestDox('assertIsNumeric()')] +#[Small] +final class assertIsNumericTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['123'], + ['123.456'], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [null], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsNumeric($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsNumeric($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsObjectTest.php b/tests/unit/Framework/Assert/assertIsObjectTest.php new file mode 100644 index 00000000000..f5f550440f5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsObjectTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsObject')] +#[TestDox('assertIsObject()')] +#[Small] +final class assertIsObjectTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsObject(new stdClass); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsObject($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsReadableTest.php b/tests/unit/Framework/Assert/assertIsReadableTest.php new file mode 100644 index 00000000000..3e278262308 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsReadableTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function chmod; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function tempnam; +use function uniqid; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsReadable')] +#[TestDox('assertIsReadable()')] +#[Small] +final class assertIsReadableTest extends TestCase +{ + private ?string $directory = null; + private ?string $file = null; + + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['directory', __DIR__], + ['file', __FILE__], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['directory', sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true)], + ['file', tempnam(sys_get_temp_dir(), __CLASS__)], + ]; + } + + protected function tearDown(): void + { + if ($this->directory !== null) { + rmdir($this->directory); + } + + if ($this->file !== null) { + unlink($this->file); + } + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, string $path): void + { + $this->assertIsReadable($path); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, string $path): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + if ($type === 'directory') { + mkdir($path, octdec('0')); + + $this->directory = $path; + } else { + chmod($path, octdec('0')); + + $this->file = $path; + } + + $this->expectException(AssertionFailedError::class); + + $this->assertIsReadable($path); + } +} diff --git a/tests/unit/Framework/Assert/assertIsResourceTest.php b/tests/unit/Framework/Assert/assertIsResourceTest.php new file mode 100644 index 00000000000..37e475debb3 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsResourceTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsResource')] +#[TestDox('assertIsResource()')] +#[Small] +final class assertIsResourceTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [$openResource], + [$closedResource], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [true], + [0.0], + [0], + [null], + ['123'], + ['string'], + [new stdClass], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsResource($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsResource($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsScalarTest.php b/tests/unit/Framework/Assert/assertIsScalarTest.php new file mode 100644 index 00000000000..4d3164c2752 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsScalarTest.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsScalar')] +#[TestDox('assertIsScalar()')] +#[Small] +final class assertIsScalarTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [true], + [false], + [0], + [0.0], + ['string'], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [null], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertIsScalar($actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsScalar($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsStringTest.php b/tests/unit/Framework/Assert/assertIsStringTest.php new file mode 100644 index 00000000000..fb9ef44a051 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsStringTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertIsString')] +#[TestDox('assertIsString()')] +#[Small] +final class assertIsStringTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [[]], + [true], + [0.0], + [0], + [null], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertIsString('string'); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertIsString($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertIsWritableTest.php b/tests/unit/Framework/Assert/assertIsWritableTest.php new file mode 100644 index 00000000000..00e27b3db29 --- /dev/null +++ b/tests/unit/Framework/Assert/assertIsWritableTest.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const DIRECTORY_SEPARATOR; +use const PHP_OS_FAMILY; +use function chmod; +use function mkdir; +use function octdec; +use function rmdir; +use function sys_get_temp_dir; +use function tempnam; +use function uniqid; +use function unlink; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertIsWritable')] +#[TestDox('assertIsWritable()')] +#[Small] +final class assertIsWritableTest extends TestCase +{ + private ?string $directory = null; + private ?string $file = null; + + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['directory', __DIR__], + ['file', __FILE__], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['directory', sys_get_temp_dir() . DIRECTORY_SEPARATOR . uniqid(__CLASS__ . '_', true)], + ['file', tempnam(sys_get_temp_dir(), __CLASS__)], + ]; + } + + protected function tearDown(): void + { + if ($this->directory !== null) { + rmdir($this->directory); + } + + if ($this->file !== null) { + unlink($this->file); + } + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $type, string $path): void + { + $this->assertIsWritable($path); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $type, string $path): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + if ($type === 'directory') { + mkdir($path, octdec('0')); + + $this->directory = $path; + } else { + chmod($path, octdec('0')); + + $this->file = $path; + } + + $this->expectException(AssertionFailedError::class); + + $this->assertIsWritable($path); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonFileEqualsJsonFileTest.php b/tests/unit/Framework/Assert/assertJsonFileEqualsJsonFileTest.php new file mode 100644 index 00000000000..ef4c485ee76 --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonFileEqualsJsonFileTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonFileEqualsJsonFile')] +#[TestDox('assertJsonFileEqualsJsonFile()')] +#[Small] +final class assertJsonFileEqualsJsonFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertJsonFileEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/simpleObject.json', + TEST_FILES_PATH . 'JsonData/simpleObject.json', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonFileEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/arrayObject.json', + TEST_FILES_PATH . 'JsonData/simpleObject.json', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonFileNotEqualsJsonFileTest.php b/tests/unit/Framework/Assert/assertJsonFileNotEqualsJsonFileTest.php new file mode 100644 index 00000000000..a9dc84a1a2f --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonFileNotEqualsJsonFileTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonFileNotEqualsJsonFile')] +#[TestDox('assertJsonFileNotEqualsJsonFile()')] +#[Small] +final class assertJsonFileNotEqualsJsonFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertJsonFileNotEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/arrayObject.json', + TEST_FILES_PATH . 'JsonData/simpleObject.json', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonFileNotEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/simpleObject.json', + TEST_FILES_PATH . 'JsonData/simpleObject.json', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonStringEqualsJsonFileTest.php b/tests/unit/Framework/Assert/assertJsonStringEqualsJsonFileTest.php new file mode 100644 index 00000000000..90df937a830 --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonStringEqualsJsonFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function json_encode; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonStringEqualsJsonFile')] +#[TestDox('assertJsonStringEqualsJsonFile()')] +#[Small] +final class assertJsonStringEqualsJsonFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertJsonStringEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/simpleObject.json', + json_encode(['Mascott' => 'Tux']), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonStringEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/arrayObject.json', + json_encode(['Mascott' => 'Tux']), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonStringEqualsJsonStringTest.php b/tests/unit/Framework/Assert/assertJsonStringEqualsJsonStringTest.php new file mode 100644 index 00000000000..9c165b1d8e9 --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonStringEqualsJsonStringTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonStringEqualsJsonString')] +#[TestDox('assertJsonStringEqualsJsonString()')] +#[Small] +final class assertJsonStringEqualsJsonStringTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['{"Mascot" : "elePHPant"}', '{"Mascot" : "elePHPant"}'], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['{"Mascot" : "elePHPant"}', '{"Mascot" : "Tux"}'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expectedJson, string $actualJson): void + { + $this->assertJsonStringEqualsJsonString($expectedJson, $actualJson); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expectedJson, string $actualJson): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonStringEqualsJsonString($expectedJson, $actualJson); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonFileTest.php b/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonFileTest.php new file mode 100644 index 00000000000..e24fcd0baa3 --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function json_encode; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonStringNotEqualsJsonFile')] +#[TestDox('assertJsonStringNotEqualsJsonFile()')] +#[Small] +final class assertJsonStringNotEqualsJsonFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertJsonStringNotEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/arrayObject.json', + json_encode(['Mascott' => 'Tux']), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonStringNotEqualsJsonFile( + TEST_FILES_PATH . 'JsonData/simpleObject.json', + json_encode(['Mascott' => 'Tux']), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonStringTest.php b/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonStringTest.php new file mode 100644 index 00000000000..58014817069 --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonStringNotEqualsJsonStringTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJsonStringNotEqualsJsonString')] +#[TestDox('assertJsonStringNotEqualsJsonString()')] +#[Small] +final class assertJsonStringNotEqualsJsonStringTest extends TestCase +{ + #[DataProviderExternal(assertJsonStringEqualsJsonStringTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expectedJson, string $actualJson): void + { + $this->assertJsonStringNotEqualsJsonString($expectedJson, $actualJson); + } + + #[DataProviderExternal(assertJsonStringEqualsJsonStringTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expectedJson, string $actualJson): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJsonStringNotEqualsJsonString($expectedJson, $actualJson); + } +} diff --git a/tests/unit/Framework/Assert/assertJsonTest.php b/tests/unit/Framework/Assert/assertJsonTest.php new file mode 100644 index 00000000000..eff3daec61c --- /dev/null +++ b/tests/unit/Framework/Assert/assertJsonTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertJson')] +#[TestDox('assertJson()')] +#[Small] +final class assertJsonTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertJson('{}'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertJson(''); + } +} diff --git a/tests/unit/Framework/Assert/assertLessThanOrEqualTest.php b/tests/unit/Framework/Assert/assertLessThanOrEqualTest.php new file mode 100644 index 00000000000..faa7e1dbd12 --- /dev/null +++ b/tests/unit/Framework/Assert/assertLessThanOrEqualTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertLessThanOrEqual')] +#[TestDox('assertLessThanOrEqual()')] +#[Small] +final class assertLessThanOrEqualTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertLessThanOrEqual(2, 1); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertLessThanOrEqual(1, 2); + } +} diff --git a/tests/unit/Framework/Assert/assertLessThanTest.php b/tests/unit/Framework/Assert/assertLessThanTest.php new file mode 100644 index 00000000000..ab46dd699d2 --- /dev/null +++ b/tests/unit/Framework/Assert/assertLessThanTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertLessThan')] +#[TestDox('assertLessThan()')] +#[Small] +final class assertLessThanTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertLessThan(2, 1); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertLessThan(1, 2); + } +} diff --git a/tests/unit/Framework/Assert/assertMatchesRegularExpressionTest.php b/tests/unit/Framework/Assert/assertMatchesRegularExpressionTest.php new file mode 100644 index 00000000000..e38ebba7efe --- /dev/null +++ b/tests/unit/Framework/Assert/assertMatchesRegularExpressionTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertMatchesRegularExpression')] +#[TestDox('assertMatchesRegularExpression()')] +#[Small] +final class assertMatchesRegularExpressionTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['/foo/', 'foobar'], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['/foo/', 'bar'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $pattern, string $string): void + { + $this->assertMatchesRegularExpression($pattern, $string); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $pattern, string $string): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertMatchesRegularExpression($pattern, $string); + } +} diff --git a/tests/unit/Framework/Assert/assertNanTest.php b/tests/unit/Framework/Assert/assertNanTest.php new file mode 100644 index 00000000000..663d450daab --- /dev/null +++ b/tests/unit/Framework/Assert/assertNanTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const NAN; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNan')] +#[TestDox('assertNan()')] +#[Small] +final class assertNanTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertNan(NAN); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNan(1); + } +} diff --git a/tests/unit/Framework/Assert/assertNotContainsEqualsTest.php b/tests/unit/Framework/Assert/assertNotContainsEqualsTest.php new file mode 100644 index 00000000000..a3cd59ea5d9 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotContainsEqualsTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotContainsEquals')] +#[TestDox('assertNotContainsEquals()')] +#[Small] +final class assertNotContainsEqualsTest extends TestCase +{ + #[DataProviderExternal(assertContainsEqualsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $needle, iterable $haystack): void + { + $this->assertNotContainsEquals($needle, $haystack); + } + + #[DataProviderExternal(assertContainsEqualsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $needle, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotContainsEquals($needle, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertNotContainsTest.php b/tests/unit/Framework/Assert/assertNotContainsTest.php new file mode 100644 index 00000000000..5db7c369e77 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotContainsTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotContains')] +#[TestDox('assertNotContains()')] +#[Small] +final class assertNotContainsTest extends TestCase +{ + #[DataProviderExternal(assertContainsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $needle, iterable $haystack): void + { + $this->assertNotContains($needle, $haystack); + } + + #[DataProviderExternal(assertContainsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $needle, iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotContains($needle, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertNotCountTest.php b/tests/unit/Framework/Assert/assertNotCountTest.php new file mode 100644 index 00000000000..fa44c0ef5e1 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotCountTest.php @@ -0,0 +1,47 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function PHPUnit\TestFixture\Generator\f; +use Countable; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotCount')] +#[CoversClass(GeneratorNotSupportedException::class)] +#[TestDox('assertNotCount()')] +#[Small] +final class assertNotCountTest extends TestCase +{ + #[DataProviderExternal(assertCountTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(int $expectedCount, Countable|iterable $haystack): void + { + $this->assertNotCount($expectedCount, $haystack); + } + + #[DataProviderExternal(assertCountTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(int $expectedCount, Countable|iterable $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotCount($expectedCount, $haystack); + } + + public function testDoesNotSupportGenerators(): void + { + $this->expectException(GeneratorNotSupportedException::class); + $this->expectExceptionMessage('Passing an argument of type Generator for the $haystack parameter is not supported'); + + $this->assertNotCount(0, f()); + } +} diff --git a/tests/unit/Framework/Assert/assertNotEmptyTest.php b/tests/unit/Framework/Assert/assertNotEmptyTest.php new file mode 100644 index 00000000000..c2be7c81c49 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotEmptyTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function PHPUnit\TestFixture\Generator\f; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotEmpty')] +#[CoversClass(GeneratorNotSupportedException::class)] +#[TestDox('assertNotEmpty()')] +#[Small] +final class assertNotEmptyTest extends TestCase +{ + #[DataProviderExternal(assertEmptyTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertNotEmpty($actual); + } + + #[DataProviderExternal(assertEmptyTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotEmpty($actual); + } + + public function testDoesNotSupportGenerators(): void + { + $this->expectException(GeneratorNotSupportedException::class); + $this->expectExceptionMessage('Passing an argument of type Generator for the $actual parameter is not supported'); + + $this->assertNotEmpty(f()); + } +} diff --git a/tests/unit/Framework/Assert/assertNotEqualsCanonicalizingTest.php b/tests/unit/Framework/Assert/assertNotEqualsCanonicalizingTest.php new file mode 100644 index 00000000000..534a9d62e04 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotEqualsCanonicalizingTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotEqualsCanonicalizing')] +#[TestDox('assertNotEqualsCanonicalizing()')] +#[Small] +final class assertNotEqualsCanonicalizingTest extends TestCase +{ + #[DataProviderExternal(assertEqualsCanonicalizingTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertNotEqualsCanonicalizing($expected, $actual); + } + + #[DataProviderExternal(assertEqualsCanonicalizingTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotEqualsCanonicalizing($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertNotEqualsIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertNotEqualsIgnoringCaseTest.php new file mode 100644 index 00000000000..896515b3dd1 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotEqualsIgnoringCaseTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotEqualsIgnoringCase')] +#[TestDox('assertNotEqualsIgnoringCase()')] +#[Small] +final class assertNotEqualsIgnoringCaseTest extends TestCase +{ + #[DataProviderExternal(assertEqualsIgnoringCaseTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertNotEqualsIgnoringCase($expected, $actual); + } + + #[DataProviderExternal(assertEqualsIgnoringCaseTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotEqualsIgnoringCase($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertNotEqualsTest.php b/tests/unit/Framework/Assert/assertNotEqualsTest.php new file mode 100644 index 00000000000..051eddf297b --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotEqualsTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotEquals')] +#[TestDox('assertNotEquals()')] +#[Small] +final class assertNotEqualsTest extends TestCase +{ + #[DataProviderExternal(assertEqualsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertNotEquals($expected, $actual); + } + + #[DataProviderExternal(assertEqualsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotEquals($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertNotEqualsWithDeltaTest.php b/tests/unit/Framework/Assert/assertNotEqualsWithDeltaTest.php new file mode 100644 index 00000000000..0b7b5026f58 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotEqualsWithDeltaTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotEqualsWithDelta')] +#[TestDox('assertNotEqualsWithDelta()')] +#[Small] +final class assertNotEqualsWithDeltaTest extends TestCase +{ + #[DataProviderExternal(assertEqualsWithDeltaTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual, float $delta): void + { + $this->assertNotEqualsWithDelta($expected, $actual, $delta); + } + + #[DataProviderExternal(assertEqualsWithDeltaTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual, float $delta): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotEqualsWithDelta($expected, $actual, $delta); + } +} diff --git a/tests/unit/Framework/Assert/assertNotFalseTest.php b/tests/unit/Framework/Assert/assertNotFalseTest.php new file mode 100644 index 00000000000..e1c8630f9c3 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotFalseTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotFalse')] +#[TestDox('assertNotFalse()')] +#[Small] +final class assertNotFalseTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [true], + [null], + [0], + [1], + ['false'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertNotFalse($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotFalse(false); + } +} diff --git a/tests/unit/Framework/Assert/assertNotInstanceOfTest.php b/tests/unit/Framework/Assert/assertNotInstanceOfTest.php new file mode 100644 index 00000000000..15444700e77 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotInstanceOfTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertNotInstanceOf')] +#[TestDox('assertNotInstanceOf()')] +#[Small] +final class assertNotInstanceOfTest extends TestCase +{ + #[DataProviderExternal(assertInstanceOfTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expected, mixed $actual): void + { + $this->assertNotInstanceOf($expected, $actual); + } + + #[DataProviderExternal(assertInstanceOfTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotInstanceOf($expected, $actual); + } + + public function testDoesNotSupportUnknownTypes(): void + { + $this->expectException(UnknownClassOrInterfaceException::class); + $this->expectExceptionMessage('Class or interface "does-not-exist" does not exist'); + + $this->assertNotInstanceOf('does-not-exist', new stdClass); + } +} diff --git a/tests/unit/Framework/Assert/assertNotNullTest.php b/tests/unit/Framework/Assert/assertNotNullTest.php new file mode 100644 index 00000000000..bdfd9961252 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotNullTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotNull')] +#[TestDox('assertNotNull()')] +#[Small] +final class assertNotNullTest extends TestCase +{ + #[DataProviderExternal(assertNullTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertNotNull($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotNull(null); + } +} diff --git a/tests/unit/Framework/Assert/assertNotSameSizeTest.php b/tests/unit/Framework/Assert/assertNotSameSizeTest.php new file mode 100644 index 00000000000..15c8da95874 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotSameSizeTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use Countable; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotSameSize')] +#[TestDox('assertNotSameSize()')] +#[Small] +final class assertNotSameSizeTest extends TestCase +{ + #[DataProviderExternal(assertSameSizeTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->assertNotSameSize($expected, $actual); + } + + #[DataProviderExternal(assertSameSizeTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotSameSize($expected, $actual); + } + + #[DataProviderExternal(assertSameSizeTest::class, 'errorProvider')] + public function testDoesNotSupportGenerators(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->expectException(GeneratorNotSupportedException::class); + + $this->assertNotSameSize($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertNotSameTest.php b/tests/unit/Framework/Assert/assertNotSameTest.php new file mode 100644 index 00000000000..46e38a1c3ad --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotSameTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotSame')] +#[TestDox('assertNotSame()')] +#[Small] +final class assertNotSameTest extends TestCase +{ + #[DataProviderExternal(assertSameTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertNotSame($expected, $actual); + } + + #[DataProviderExternal(assertSameTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotSame($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertNotTrueTest.php b/tests/unit/Framework/Assert/assertNotTrueTest.php new file mode 100644 index 00000000000..8a701859143 --- /dev/null +++ b/tests/unit/Framework/Assert/assertNotTrueTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertNotTrue')] +#[TestDox('assertNotTrue()')] +#[Small] +final class assertNotTrueTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [false], + [null], + [0], + [1], + ['true'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $actual): void + { + $this->assertNotTrue($actual); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNotTrue(true); + } +} diff --git a/tests/unit/Framework/Assert/assertNullTest.php b/tests/unit/Framework/Assert/assertNullTest.php new file mode 100644 index 00000000000..69c69920cba --- /dev/null +++ b/tests/unit/Framework/Assert/assertNullTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertNull')] +#[TestDox('assertNull()')] +#[Small] +final class assertNullTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + $openResource = fopen(__FILE__, 'r'); + + $closedResource = fopen(__FILE__, 'r'); + fclose($closedResource); + + return [ + [['foo' => 'bar']], + [[1 => 'bar', 4 => 'baz']], + [true], + [0.0], + [0], + ['123'], + ['string'], + [new stdClass], + [$openResource], + [$closedResource], + ]; + } + + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertNull(null); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertNull($actual); + } +} diff --git a/tests/unit/Framework/Assert/assertObjectEqualsTest.php b/tests/unit/Framework/Assert/assertObjectEqualsTest.php new file mode 100644 index 00000000000..a25fd26e541 --- /dev/null +++ b/tests/unit/Framework/Assert/assertObjectEqualsTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\TestFixture\ObjectEquals\ValueObject; + +#[CoversMethod(Assert::class, 'assertObjectEquals')] +#[TestDox('assertObjectEquals()')] +#[Small] +final class assertObjectEqualsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [new ValueObject(1), new ValueObject(1), 'equals'], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [new ValueObject(1), new ValueObject(2), 'equals'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(object $expected, object $actual, string $method): void + { + $this->assertObjectEquals($expected, $actual, $method); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(object $expected, object $actual, string $method): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertObjectEquals($expected, $actual, $method); + } +} diff --git a/tests/unit/Framework/Assert/assertObjectHasPropertyTest.php b/tests/unit/Framework/Assert/assertObjectHasPropertyTest.php new file mode 100644 index 00000000000..767e8fc00d8 --- /dev/null +++ b/tests/unit/Framework/Assert/assertObjectHasPropertyTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertObjectHasProperty')] +#[TestDox('assertObjectHasProperty()')] +#[Small] +final class assertObjectHasPropertyTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $object = new stdClass; + $object->theProperty = 'value'; + + $this->assertObjectHasProperty('theProperty', $object); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $object = new stdClass; + + $this->expectException(AssertionFailedError::class); + + $this->assertObjectHasProperty('theProperty', $object); + } +} diff --git a/tests/unit/Framework/Assert/assertObjectNotEqualsTest.php b/tests/unit/Framework/Assert/assertObjectNotEqualsTest.php new file mode 100644 index 00000000000..7c65ce0e495 --- /dev/null +++ b/tests/unit/Framework/Assert/assertObjectNotEqualsTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertObjectNotEquals')] +#[TestDox('assertObjectNotEquals()')] +#[Small] +final class assertObjectNotEqualsTest extends TestCase +{ + #[DataProviderExternal(assertObjectEqualsTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(object $expected, object $actual, string $method): void + { + $this->assertObjectNotEquals($expected, $actual, $method); + } + + #[DataProviderExternal(assertObjectEqualsTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(object $expected, object $actual, string $method): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertObjectNotEquals($expected, $actual, $method); + } +} diff --git a/tests/unit/Framework/Assert/assertObjectNotHasPropertyTest.php b/tests/unit/Framework/Assert/assertObjectNotHasPropertyTest.php new file mode 100644 index 00000000000..ef15842ccba --- /dev/null +++ b/tests/unit/Framework/Assert/assertObjectNotHasPropertyTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use stdClass; + +#[CoversMethod(Assert::class, 'assertObjectNotHasProperty')] +#[TestDox('assertObjectNotHasProperty()')] +#[Small] +final class assertObjectNotHasPropertyTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $object = new stdClass; + + $this->assertObjectNotHasProperty('theProperty', $object); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $object = new stdClass; + $object->theProperty = 'value'; + + $this->expectException(AssertionFailedError::class); + + $this->assertObjectNotHasProperty('theProperty', $object); + } +} diff --git a/tests/unit/Framework/Assert/assertSameSizeTest.php b/tests/unit/Framework/Assert/assertSameSizeTest.php new file mode 100644 index 00000000000..671d4d93e3d --- /dev/null +++ b/tests/unit/Framework/Assert/assertSameSizeTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function PHPUnit\TestFixture\Generator\f; +use Countable; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertSameSize')] +#[CoversClass(GeneratorNotSupportedException::class)] +#[TestDox('assertSameSize()')] +#[Small] +final class assertSameSizeTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + [[1, 2], [3, 4]], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + [[1, 2], [3]], + ]; + } + + /** + * @return non-empty-list + */ + public static function errorProvider(): array + { + return [ + [f(), []], + [[], f()], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->assertSameSize($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertSameSize($expected, $actual); + } + + #[DataProvider('errorProvider')] + public function testDoesNotSupportGenerators(Countable|iterable $expected, Countable|iterable $actual): void + { + $this->expectException(GeneratorNotSupportedException::class); + + $this->assertSameSize($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertSameTest.php b/tests/unit/Framework/Assert/assertSameTest.php new file mode 100644 index 00000000000..db0e0c45d77 --- /dev/null +++ b/tests/unit/Framework/Assert/assertSameTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const INF; +use function array_merge; +use function fopen; +use function log; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\TestFixture\SampleClass; + +#[CoversMethod(Assert::class, 'assertSame')] +#[TestDox('assertSame()')] +#[Small] +final class assertSameTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return self::sameValues(); + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return array_merge(assertEqualsTest::notEqualValues(), assertEqualsTest::equalValues()); + } + + /** + * @return non-empty-list + */ + public static function sameValues(): array + { + $object = new SampleClass(4, 8, 15); + $file = TEST_FILES_PATH . 'foo.xml'; + $resource = fopen($file, 'r'); + + return [ + // null + [null, null], + // strings + ['a', 'a'], + // integers + [0, 0], + // floats + [1.0, 1.0], + [2.3, 2.3], + [1 / 3, 1 / 3], + [1 - 2 / 3, 1 - 2 / 3], + [5.5E+123, 5.5E+123], + [5.5E-123, 5.5E-123], + [log(0), log(0)], + [INF, INF], + [-INF, -INF], + // arrays + [[], []], + [[0 => 1], [0 => 1]], + [[0 => null], [0 => null]], + [['a', 'b' => [1, 2]], ['a', 'b' => [1, 2]]], + // objects + [$object, $object], + // resources + [$resource, $resource], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(mixed $expected, mixed $actual): void + { + $this->assertSame($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(mixed $expected, mixed $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertSame($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertStringContainsStringIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertStringContainsStringIgnoringCaseTest.php new file mode 100644 index 00000000000..ae696ed00fa --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringContainsStringIgnoringCaseTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringContainsStringIgnoringCase')] +#[TestDox('assertStringContainsStringIgnoringCase()')] +#[Small] +final class assertStringContainsStringIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringContainsStringIgnoringCase('BAR', 'foobarbaz'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringContainsStringIgnoringCase('BARBARA', 'foobarbaz'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringContainsStringIgnoringLineEndingsTest.php b/tests/unit/Framework/Assert/assertStringContainsStringIgnoringLineEndingsTest.php new file mode 100644 index 00000000000..b7d2c1a764b --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringContainsStringIgnoringLineEndingsTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringContainsStringIgnoringLineEndings')] +#[TestDox('assertStringContainsStringIgnoringLineEndings()')] +#[Small] +final class assertStringContainsStringIgnoringLineEndingsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ["b\nc", "b\r\nc"], + ["b\nc", "a\r\nb\r\nc\r\nd"], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ["a\nc", "b\r\nc"], + ["a\nc", "a\r\nb\r\nc\r\nd"], + ["b\nc", "\r\nc\r\n"], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $needle, string $haystack): void + { + $this->assertStringContainsStringIgnoringLineEndings($needle, $haystack); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $needle, string $haystack): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringContainsStringIgnoringLineEndings($needle, $haystack); + } +} diff --git a/tests/unit/Framework/Assert/assertStringContainsStringTest.php b/tests/unit/Framework/Assert/assertStringContainsStringTest.php new file mode 100644 index 00000000000..8b5276e4bb5 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringContainsStringTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringContainsString')] +#[TestDox('assertStringContainsString()')] +#[Small] +final class assertStringContainsStringTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringContainsString('bar', 'foobarbaz'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringContainsString('barbara', 'foobarbaz'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEndsNotWithTest.php b/tests/unit/Framework/Assert/assertStringEndsNotWithTest.php new file mode 100644 index 00000000000..9e3d4e567ba --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEndsNotWithTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEndsNotWith')] +#[TestDox('assertStringEndsNotWith()')] +#[Small] +final class assertStringEndsNotWithTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringEndsNotWith('suffix', 'foo'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEndsNotWith('suffix', 'foosuffix'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEndsWithTest.php b/tests/unit/Framework/Assert/assertStringEndsWithTest.php new file mode 100644 index 00000000000..0c8e264dd90 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEndsWithTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEndsWith')] +#[TestDox('assertStringEndsWith()')] +#[Small] +final class assertStringEndsWithTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringEndsWith('suffix', 'foosuffix'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEndsWith('suffix', 'foo'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEqualsFileCanonicalizingTest.php b/tests/unit/Framework/Assert/assertStringEqualsFileCanonicalizingTest.php new file mode 100644 index 00000000000..f4bf4074b49 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEqualsFileCanonicalizingTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEqualsFileCanonicalizing')] +#[TestDox('assertStringEqualsFileCanonicalizing()')] +#[Small] +final class assertStringEqualsFileCanonicalizingTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringEqualsFileCanonicalizing( + TEST_FILES_PATH . 'foo.txt', + file_get_contents(TEST_FILES_PATH . 'foo.txt'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEqualsFileCanonicalizing( + TEST_FILES_PATH . 'foo.txt', + file_get_contents(TEST_FILES_PATH . 'foo.txt') . 'BAR', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEqualsFileIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertStringEqualsFileIgnoringCaseTest.php new file mode 100644 index 00000000000..d1db2408ce4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEqualsFileIgnoringCaseTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEqualsFileIgnoringCase')] +#[TestDox('assertStringEqualsFileIgnoringCase()')] +#[Small] +final class assertStringEqualsFileIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringEqualsFileIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'fooUppercase.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEqualsFileIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEqualsFileTest.php b/tests/unit/Framework/Assert/assertStringEqualsFileTest.php new file mode 100644 index 00000000000..0b53771844a --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEqualsFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEqualsFile')] +#[TestDox('assertStringEqualsFile()')] +#[Small] +final class assertStringEqualsFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringEqualsFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'foo.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEqualsFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringEqualsStringIgnoringLineEndingsTest.php b/tests/unit/Framework/Assert/assertStringEqualsStringIgnoringLineEndingsTest.php new file mode 100644 index 00000000000..5123272c528 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringEqualsStringIgnoringLineEndingsTest.php @@ -0,0 +1,65 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringEqualsStringIgnoringLineEndings')] +#[TestDox('assertStringEqualsStringIgnoringLineEndings()')] +#[Small] +final class assertStringEqualsStringIgnoringLineEndingsTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ["a\nb", "a\r\nb"], + ["a\rb", "a\r\nb"], + ["a\r\nb", "a\r\nb"], + ["a\nb", "a\rb"], + ["a\rb", "a\rb"], + ["a\r\nb", "a\rb"], + ["a\nb", "a\nb"], + ["a\rb", "a\nb"], + ["a\r\nb", "a\nb"], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ["a\nb", 'ab'], + ["a\rb", 'ab'], + ["a\r\nb", 'ab'], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expected, string $actual): void + { + $this->assertStringEqualsStringIgnoringLineEndings($expected, $actual); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expected, string $actual): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringEqualsStringIgnoringLineEndings($expected, $actual); + } +} diff --git a/tests/unit/Framework/Assert/assertStringMatchesFormatFileTest.php b/tests/unit/Framework/Assert/assertStringMatchesFormatFileTest.php new file mode 100644 index 00000000000..a19a60fab42 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringMatchesFormatFileTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringMatchesFormatFile')] +#[TestDox('assertStringMatchesFormatFile()')] +#[Small] +final class assertStringMatchesFormatFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringMatchesFormatFile(TEST_FILES_PATH . 'expectedFileFormat.txt', "FOO\n"); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringMatchesFormatFile(TEST_FILES_PATH . 'expectedFileFormat.txt', "BAR\n"); + } +} diff --git a/tests/unit/Framework/Assert/assertStringMatchesFormatTest.php b/tests/unit/Framework/Assert/assertStringMatchesFormatTest.php new file mode 100644 index 00000000000..5e9d80394e8 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringMatchesFormatTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringMatchesFormat')] +#[TestDox('assertStringMatchesFormat()')] +#[Small] +final class assertStringMatchesFormatTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringMatchesFormat('*%s*', '***'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringMatchesFormat('*%s*', '**'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringNotContainsStringIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertStringNotContainsStringIgnoringCaseTest.php new file mode 100644 index 00000000000..00cb4b23ece --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringNotContainsStringIgnoringCaseTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringNotContainsStringIgnoringCase')] +#[TestDox('assertStringNotContainsStringIgnoringCase()')] +#[Small] +final class assertStringNotContainsStringIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringNotContainsStringIgnoringCase('BARBARA', 'foobarbaz'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringNotContainsStringIgnoringCase('BAR', 'foobarbaz'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringNotContainsStringTest.php b/tests/unit/Framework/Assert/assertStringNotContainsStringTest.php new file mode 100644 index 00000000000..9ec048bd002 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringNotContainsStringTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringNotContainsString')] +#[TestDox('assertStringNotContainsString()')] +#[Small] +final class assertStringNotContainsStringTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringNotContainsString('barbara', 'foobarbaz'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringNotContainsString('bar', 'foobarbaz'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringNotEqualsFileCanonicalizingTest.php b/tests/unit/Framework/Assert/assertStringNotEqualsFileCanonicalizingTest.php new file mode 100644 index 00000000000..b8cd2f85f80 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringNotEqualsFileCanonicalizingTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringNotEqualsFileCanonicalizing')] +#[TestDox('assertStringNotEqualsFileCanonicalizing()')] +#[Small] +final class assertStringNotEqualsFileCanonicalizingTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringNotEqualsFileCanonicalizing( + TEST_FILES_PATH . 'foo.txt', + file_get_contents(TEST_FILES_PATH . 'foo.txt') . 'BAR', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringNotEqualsFileCanonicalizing( + TEST_FILES_PATH . 'foo.txt', + file_get_contents(TEST_FILES_PATH . 'foo.txt'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringNotEqualsFileIgnoringCaseTest.php b/tests/unit/Framework/Assert/assertStringNotEqualsFileIgnoringCaseTest.php new file mode 100644 index 00000000000..da141ba288a --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringNotEqualsFileIgnoringCaseTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringNotEqualsFileIgnoringCase')] +#[TestDox('assertStringNotEqualsFileIgnoringCase()')] +#[Small] +final class assertStringNotEqualsFileIgnoringCaseTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringNotEqualsFileIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringNotEqualsFileIgnoringCase( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'fooUppercase.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringNotEqualsFileTest.php b/tests/unit/Framework/Assert/assertStringNotEqualsFileTest.php new file mode 100644 index 00000000000..5effdea0155 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringNotEqualsFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringNotEqualsFile')] +#[TestDox('assertStringNotEqualsFile()')] +#[Small] +final class assertStringNotEqualsFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringNotEqualsFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringNotEqualsFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'foo.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertStringStartsNotWithTest.php b/tests/unit/Framework/Assert/assertStringStartsNotWithTest.php new file mode 100644 index 00000000000..4646f27d57e --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringStartsNotWithTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringStartsNotWith')] +#[TestDox('assertStringStartsNotWith()')] +#[Small] +final class assertStringStartsNotWithTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringStartsNotWith('prefix', 'foo'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringStartsNotWith('prefix', 'prefixfoo'); + } +} diff --git a/tests/unit/Framework/Assert/assertStringStartsWithTest.php b/tests/unit/Framework/Assert/assertStringStartsWithTest.php new file mode 100644 index 00000000000..d17898edcf8 --- /dev/null +++ b/tests/unit/Framework/Assert/assertStringStartsWithTest.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertStringStartsWith')] +#[TestDox('assertStringStartsWith()')] +#[Small] +final class assertStringStartsWithTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertStringStartsWith('prefix', 'prefixfoo'); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertStringStartsWith('prefix', 'foo'); + } +} diff --git a/tests/unit/Framework/Assert/assertThatTest.php b/tests/unit/Framework/Assert/assertThatTest.php new file mode 100644 index 00000000000..cc517bd2cd8 --- /dev/null +++ b/tests/unit/Framework/Assert/assertThatTest.php @@ -0,0 +1,395 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use const INF; +use const NAN; +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\TestFixture\Book; +use PHPUnit\TestFixture\ObjectEquals\ValueObject; +use stdClass; + +#[CoversClass(Assert::class)] +#[TestDox('assertThat()')] +#[Small] +final class assertThatTest extends TestCase +{ + #[DoesNotPerformAssertions] + public function testAssertThatAnything(): void + { + $this->assertThat('anything', $this->anything()); + } + + public function testAssertThatIsTrue(): void + { + $this->assertThat(true, $this->isTrue()); + } + + public function testAssertThatIsFalse(): void + { + $this->assertThat(false, $this->isFalse()); + } + + public function testAssertThatIsJson(): void + { + $this->assertThat('{}', $this->isJson()); + } + + #[DoesNotPerformAssertions] + public function testAssertThatAnythingAndAnything(): void + { + $this->assertThat( + 'anything', + $this->logicalAnd( + $this->anything(), + $this->anything(), + ), + ); + } + + #[DoesNotPerformAssertions] + public function testAssertThatAnythingOrAnything(): void + { + $this->assertThat( + 'anything', + $this->logicalOr( + $this->anything(), + $this->anything(), + ), + ); + } + + #[DoesNotPerformAssertions] + public function testAssertThatAnythingXorNotAnything(): void + { + $this->assertThat( + 'anything', + $this->logicalXor( + $this->anything(), + $this->logicalNot($this->anything()), + ), + ); + } + + public function testAssertThatContainsEqual(): void + { + $this->assertThat(['foo'], $this->containsEqual('foo')); + } + + public function testAssertThatContainsIdentical(): void + { + $this->assertThat(['foo'], $this->containsIdentical('foo')); + } + + public function testAssertThatStringMatchesFormatDescription(): void + { + $this->assertThat('foo', $this->matches('%s')); + } + + public function testAssertThatStringContains(): void + { + $this->assertThat('barfoobar', $this->stringContains('foo')); + } + + public function testAssertThatStringStartsWith(): void + { + $this->assertThat('foobar', $this->stringStartsWith('foo')); + } + + public function testAssertThatStringEndsWith(): void + { + $this->assertThat('foobar', $this->stringEndsWith('bar')); + } + + public function testAssertThatStringEqualsStringIgnoringLineEndings(): void + { + $this->assertThat('foo' . "\r\n", $this->stringEqualsStringIgnoringLineEndings('foo' . "\n")); + } + + public function testAssertThatContainsOnlyArray(): void + { + $this->assertThat([[]], $this->containsOnlyArray()); + } + + public function testAssertThatContainsOnlyBool(): void + { + $this->assertThat([true], $this->containsOnlyBool()); + } + + public function testAssertThatContainsOnlyCallable(): void + { + $callable = static function (): void + {}; + + $this->assertThat([$callable], $this->containsOnlyCallable()); + } + + public function testAssertThatContainsOnlyFloat(): void + { + $this->assertThat([0.0], $this->containsOnlyFloat()); + } + + public function testAssertThatContainsOnlyInt(): void + { + $this->assertThat([0], $this->containsOnlyInt()); + } + + public function testAssertThatContainsOnlyIterable(): void + { + $this->assertThat([[]], $this->containsOnlyIterable()); + } + + public function testAssertThatContainsOnlyNull(): void + { + $this->assertThat([null], $this->containsOnlyNull()); + } + + public function testAssertThatContainsOnlyNumeric(): void + { + $this->assertThat(['0.0'], $this->containsOnlyNumeric()); + } + + public function testAssertThatContainsOnlyObject(): void + { + $this->assertThat([new stdClass], $this->containsOnlyObject()); + } + + public function testAssertThatContainsOnlyResource(): void + { + $resource = fopen(__FILE__, 'r'); + + $this->assertThat([$resource], $this->containsOnlyResource()); + } + + public function testAssertThatContainsOnlyClosedResource(): void + { + $resource = fopen(__FILE__, 'r'); + + fclose($resource); + + $this->assertThat([$resource], $this->containsOnlyClosedResource()); + } + + public function testAssertThatContainsOnlyScalar(): void + { + $this->assertThat(['string'], $this->containsOnlyScalar()); + } + + public function testAssertThatContainsOnlyString(): void + { + $this->assertThat(['string'], $this->containsOnlyString()); + } + + public function testAssertThatContainsOnlyInstancesOf(): void + { + $this->assertThat([new Book], $this->containsOnlyInstancesOf(Book::class)); + } + + public function testAssertThatArrayHasKey(): void + { + $this->assertThat(['foo' => 'bar'], $this->arrayHasKey('foo')); + } + + public function testAssertThatArrayIsList(): void + { + $this->assertThat([0, 1, 2], $this->isList()); + } + + public function testAssertThatEqualTo(): void + { + $this->assertThat('foo', $this->equalTo('foo')); + } + + public function testAssertThatEqualToCanonicalizing(): void + { + $this->assertThat(['foo', 'bar'], $this->equalToCanonicalizing(['bar', 'foo'])); + } + + public function testAssertThatEqualToIgnoringCase(): void + { + $this->assertThat('foo', $this->equalToIgnoringCase('FOO')); + } + + public function testAssertThatEqualToWithDelta(): void + { + $this->assertThat(1.0, $this->equalToWithDelta(1.09, 0.1)); + } + + public function testAssertThatIdenticalTo(): void + { + $value = new stdClass; + $constraint = $this->identicalTo($value); + + $this->assertThat($value, $constraint); + } + + public function testAssertThatIsInstanceOf(): void + { + $this->assertThat(new stdClass, $this->isInstanceOf(stdClass::class)); + } + + public function testAssertThatIsArray(): void + { + $this->assertThat([], $this->isArray()); + } + + public function testAssertThatIsBool(): void + { + $this->assertThat(true, $this->isBool()); + } + + public function testAssertThatIsCallable(): void + { + $this->assertThat(static function (): void + {}, $this->isCallable()); + } + + public function testAssertThatIsFloat(): void + { + $this->assertThat(0.0, $this->isFloat()); + } + + public function testAssertThatIsInt(): void + { + $this->assertThat(0, $this->isInt()); + } + + public function testAssertThatIsIterable(): void + { + $this->assertThat([], $this->isIterable()); + } + + public function testAssertThatIsNumeric(): void + { + $this->assertThat('0.0', $this->isNumeric()); + } + + public function testAssertThatIsObject(): void + { + $this->assertThat(new stdClass, $this->isObject()); + } + + public function testAssertThatIsResource(): void + { + $this->assertThat(fopen(__FILE__, 'r'), $this->isResource()); + } + + public function testAssertThatIsClosedResource(): void + { + $resource = fopen(__FILE__, 'r'); + + fclose($resource); + + $this->assertThat($resource, $this->isClosedResource()); + } + + public function testAssertThatIsScalar(): void + { + $this->assertThat('string', $this->isScalar()); + } + + public function testAssertThatIsString(): void + { + $this->assertThat('string', $this->isString()); + } + + public function testAssertThatIsEmpty(): void + { + $this->assertThat([], $this->isEmpty()); + } + + public function testAssertThatFileIsReadable(): void + { + $this->assertThat(__FILE__, $this->isReadable()); + } + + public function testAssertThatFileIsWritable(): void + { + $this->assertThat(__FILE__, $this->isWritable()); + } + + public function testAssertThatDirectoryExists(): void + { + $this->assertThat(__DIR__, $this->directoryExists()); + } + + public function testAssertThatFileExists(): void + { + $this->assertThat(__FILE__, $this->fileExists()); + } + + public function testAssertThatGreaterThan(): void + { + $this->assertThat(2, $this->greaterThan(1)); + } + + public function testAssertThatGreaterThanOrEqual(): void + { + $this->assertThat(2, $this->greaterThanOrEqual(1)); + } + + public function testAssertThatLessThan(): void + { + $this->assertThat(1, $this->lessThan(2)); + } + + public function testAssertThatLessThanOrEqual(): void + { + $this->assertThat(1, $this->lessThanOrEqual(2)); + } + + public function testAssertThatMatchesRegularExpression(): void + { + $this->assertThat('foobar', $this->matchesRegularExpression('/foo/')); + } + + public function testAssertThatCallback(): void + { + $this->assertThat( + null, + $this->callback(static fn ($other) => true), + ); + } + + public function testAssertThatCountOf(): void + { + $this->assertThat([1], $this->countOf(1)); + } + + public function testAssertThatNull(): void + { + $this->assertThat(null, $this->isNull()); + } + + public function testAssertThatIsFinite(): void + { + $this->assertThat(0, $this->isFinite()); + } + + public function testAssertThatIsInfinite(): void + { + $this->assertThat(INF, $this->isInfinite()); + } + + public function testAssertThatIsNan(): void + { + $this->assertThat(NAN, $this->isNan()); + } + + public function testAssertThatObjectEquals(): void + { + $this->assertObjectEquals(new ValueObject(1), new ValueObject(1)); + } +} diff --git a/tests/unit/Framework/Assert/assertTrueTest.php b/tests/unit/Framework/Assert/assertTrueTest.php new file mode 100644 index 00000000000..15694f81a43 --- /dev/null +++ b/tests/unit/Framework/Assert/assertTrueTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertTrue')] +#[TestDox('assertTrue()')] +#[Small] +final class assertTrueTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertTrue(true); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + /* @noinspection PhpUnitAssertCanBeReplacedWithFailInspection */ + $this->assertTrue(false); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlFileEqualsXmlFileTest.php b/tests/unit/Framework/Assert/assertXmlFileEqualsXmlFileTest.php new file mode 100644 index 00000000000..9c0c8273681 --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlFileEqualsXmlFileTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlFileEqualsXmlFile')] +#[TestDox('assertXmlFileEqualsXmlFile()')] +#[Small] +final class assertXmlFileEqualsXmlFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertXmlFileEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'foo.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlFileEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlFileNotEqualsXmlFileTest.php b/tests/unit/Framework/Assert/assertXmlFileNotEqualsXmlFileTest.php new file mode 100644 index 00000000000..7a3c46e3b1c --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlFileNotEqualsXmlFileTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlFileNotEqualsXmlFile')] +#[TestDox('assertXmlFileNotEqualsXmlFile()')] +#[Small] +final class assertXmlFileNotEqualsXmlFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertXmlFileNotEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'bar.xml', + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlFileNotEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + TEST_FILES_PATH . 'foo.xml', + ); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlStringEqualsXmlFileTest.php b/tests/unit/Framework/Assert/assertXmlStringEqualsXmlFileTest.php new file mode 100644 index 00000000000..074f0e8778c --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlStringEqualsXmlFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlStringEqualsXmlFile')] +#[TestDox('assertXmlStringEqualsXmlFile()')] +#[Small] +final class assertXmlStringEqualsXmlFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertXmlStringEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'foo.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlStringEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlStringEqualsXmlStringTest.php b/tests/unit/Framework/Assert/assertXmlStringEqualsXmlStringTest.php new file mode 100644 index 00000000000..b729fd31a1c --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlStringEqualsXmlStringTest.php @@ -0,0 +1,70 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlStringEqualsXmlString')] +#[TestDox('assertXmlStringEqualsXmlString()')] +#[Small] +final class assertXmlStringEqualsXmlStringTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function successProvider(): array + { + return [ + ['', ''], + ['', ''], + [ + <<<'XML' + + + + +XML, + <<<'XML' + + + + +XML + ], + ]; + } + + /** + * @return non-empty-list + */ + public static function failureProvider(): array + { + return [ + ['', ''], + ]; + } + + #[DataProvider('successProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expectedXml, string $actualXml): void + { + $this->assertXmlStringEqualsXmlString($expectedXml, $actualXml); + } + + #[DataProvider('failureProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expectedXml, string $actualXml): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlStringEqualsXmlString($expectedXml, $actualXml); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlFileTest.php b/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlFileTest.php new file mode 100644 index 00000000000..2e8a7721e66 --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlFileTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlStringNotEqualsXmlFile')] +#[TestDox('assertXmlStringNotEqualsXmlFile()')] +#[Small] +final class assertXmlStringNotEqualsXmlFileTest extends TestCase +{ + public function testSucceedsWhenConstraintEvaluatesToTrue(): void + { + $this->assertXmlStringNotEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'bar.xml'), + ); + } + + public function testFailsWhenConstraintEvaluatesToFalse(): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlStringNotEqualsXmlFile( + TEST_FILES_PATH . 'foo.xml', + file_get_contents(TEST_FILES_PATH . 'foo.xml'), + ); + } +} diff --git a/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlStringTest.php b/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlStringTest.php new file mode 100644 index 00000000000..f00a7d0fcf4 --- /dev/null +++ b/tests/unit/Framework/Assert/assertXmlStringNotEqualsXmlStringTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'assertXmlStringNotEqualsXmlString')] +#[TestDox('assertXmlStringNotEqualsXmlString()')] +#[Small] +final class assertXmlStringNotEqualsXmlStringTest extends TestCase +{ + #[DataProviderExternal(assertXmlStringEqualsXmlStringTest::class, 'failureProvider')] + public function testSucceedsWhenConstraintEvaluatesToTrue(string $expectedXml, string $actualXml): void + { + $this->assertXmlStringNotEqualsXmlString($expectedXml, $actualXml); + } + + #[DataProviderExternal(assertXmlStringEqualsXmlStringTest::class, 'successProvider')] + public function testFailsWhenConstraintEvaluatesToFalse(string $expectedXml, string $actualXml): void + { + $this->expectException(AssertionFailedError::class); + + $this->assertXmlStringNotEqualsXmlString($expectedXml, $actualXml); + } +} diff --git a/tests/unit/Framework/Assert/failTest.php b/tests/unit/Framework/Assert/failTest.php new file mode 100644 index 00000000000..07d15b9680c --- /dev/null +++ b/tests/unit/Framework/Assert/failTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'fail')] +#[TestDox('fail()')] +#[Small] +final class failTest extends TestCase +{ + public function testFailsTest(): void + { + $message = 'message'; + + $this->expectException(AssertionFailedError::class); + $this->expectExceptionMessage($message); + + $this->fail($message); + } +} diff --git a/tests/unit/Framework/Assert/markTestIncompleteTest.php b/tests/unit/Framework/Assert/markTestIncompleteTest.php new file mode 100644 index 00000000000..05878f58d8a --- /dev/null +++ b/tests/unit/Framework/Assert/markTestIncompleteTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'markTestIncomplete')] +#[TestDox('markTestIncomplete()')] +#[Small] +final class markTestIncompleteTest extends TestCase +{ + public function testMarksTestAsIncomplete(): void + { + $message = 'message'; + + $this->expectException(IncompleteTestError::class); + $this->expectExceptionMessage($message); + + $this->markTestIncomplete($message); + } +} diff --git a/tests/unit/Framework/Assert/markTestSkippedTest.php b/tests/unit/Framework/Assert/markTestSkippedTest.php new file mode 100644 index 00000000000..bccf8534e8a --- /dev/null +++ b/tests/unit/Framework/Assert/markTestSkippedTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; + +#[CoversMethod(Assert::class, 'markTestSkipped')] +#[TestDox('markTestSkipped()')] +#[Small] +final class markTestSkippedTest extends TestCase +{ + public function testMarksTestAsSkipped(): void + { + $message = 'message'; + + $this->expectException(SkippedWithMessageException::class); + $this->expectExceptionMessage($message); + + $this->markTestSkipped($message); + } +} diff --git a/tests/unit/Framework/Constraint/Boolean/IsFalseTest.php b/tests/unit/Framework/Constraint/Boolean/IsFalseTest.php new file mode 100644 index 00000000000..16625a2417b --- /dev/null +++ b/tests/unit/Framework/Constraint/Boolean/IsFalseTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsFalse::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsFalseTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $this->assertTrue((new IsFalse)->evaluate(false, returnResult: true)); + $this->assertFalse((new IsFalse)->evaluate(true, returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is false', (new IsFalse)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsFalse)); + } +} diff --git a/tests/unit/Framework/Constraint/Boolean/IsTrueTest.php b/tests/unit/Framework/Constraint/Boolean/IsTrueTest.php new file mode 100644 index 00000000000..38b8ec46303 --- /dev/null +++ b/tests/unit/Framework/Constraint/Boolean/IsTrueTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsTrue::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsTrueTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $this->assertTrue((new IsTrue)->evaluate(true, returnResult: true)); + $this->assertFalse((new IsTrue)->evaluate(false, returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is true', (new IsTrue)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsTrue)); + } +} diff --git a/tests/unit/Framework/Constraint/CallbackTest.php b/tests/unit/Framework/Constraint/CallbackTest.php new file mode 100644 index 00000000000..978d549659c --- /dev/null +++ b/tests/unit/Framework/Constraint/CallbackTest.php @@ -0,0 +1,81 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Callback::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class CallbackTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $this->assertTrue($this->acceptingCallbackConstraint()->evaluate('actual', returnResult: true)); + $this->assertFalse($this->rejectingCallbackConstraint()->evaluate('actual', returnResult: true)); + + try { + $this->rejectingCallbackConstraint()->evaluate('actual'); + } catch (ExpectationFailedException $e) { + $this->assertSame('Failed asserting that \'actual\' is accepted by specified callback.', $e->getMessage()); + + return; + } + + $this->fail(); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is accepted by specified callback', $this->acceptingCallbackConstraint()->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, $this->acceptingCallbackConstraint()); + } + + public function testIsVariadic(): void + { + $class = new class + { + public function __invoke(string ...$values): void + { + } + }; + + $this->assertTrue(new Callback($class)->isVariadic()); + } + + public function testIsNotVariadic(): void + { + $class = new class + { + public function __invoke(string $value): void + { + } + }; + + $this->assertFalse(new Callback($class)->isVariadic()); + } + + private function acceptingCallbackConstraint(): Callback + { + return new Callback(static fn (): bool => true); + } + + private function rejectingCallbackConstraint(): Callback + { + return new Callback(static fn (): bool => false); + } +} diff --git a/tests/unit/Framework/Constraint/Cardinality/CountTest.php b/tests/unit/Framework/Constraint/Cardinality/CountTest.php new file mode 100644 index 00000000000..8a890af4213 --- /dev/null +++ b/tests/unit/Framework/Constraint/Cardinality/CountTest.php @@ -0,0 +1,218 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use ArrayIterator; +use ArrayObject; +use EmptyIterator; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\GeneratorNotSupportedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\ExceptionThrowingIteratorAggregate; +use PHPUnit\TestFixture\TestIterator; +use PHPUnit\TestFixture\TestIterator2; +use PHPUnit\TestFixture\TestIteratorAggregate; +use PHPUnit\TestFixture\TestIteratorAggregate2; + +#[CoversClass(Count::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class CountTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 0, + [], + ], + + [ + true, + '', + 1, + ['value'], + ], + + [ + true, + '', + 0, + new EmptyIterator, + ], + + [ + true, + '', + 5, + new ArrayObject([1, 2, 3, 4, 5]), + ], + + [ + true, + '', + 1, + new ArrayIterator(['value']), + ], + + [ + true, + '', + 2, + new TestIterator(['value', 'value']), + ], + + [ + true, + '', + 2, + new TestIteratorAggregate(new TestIterator(['value', 'value'])), + ], + + [ + true, + '', + 2, + new TestIteratorAggregate2(new TestIteratorAggregate(new TestIterator(['value', 'value']))), + ], + + [ + false, + 'Failed asserting that actual size 0 matches expected size 1.', + 1, + 1, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, int $expected, mixed $actual): void + { + $constraint = new Count($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('count matches 1', new Count(1)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new Count(1))); + } + + public function testCountDoesNotChangeIteratorKey(): void + { + $countConstraint = new Count(2); + + // test with 1st implementation of Iterator + $it = new TestIterator([1, 2]); + + $countConstraint->evaluate($it, returnResult: true); + $this->assertSame(1, $it->current()); + + $it->next(); + $countConstraint->evaluate($it, returnResult: true); + $this->assertSame(2, $it->current()); + + $it->next(); + $countConstraint->evaluate($it, returnResult: true); + $this->assertFalse($it->valid()); + + // test with 2nd implementation of Iterator + $it = new TestIterator2([1, 2]); + + $countConstraint = new Count(2); + $countConstraint->evaluate($it, returnResult: true); + $this->assertSame(1, $it->current()); + + $it->next(); + $countConstraint->evaluate($it, returnResult: true); + $this->assertSame(2, $it->current()); + + $it->next(); + $countConstraint->evaluate($it, returnResult: true); + $this->assertFalse($it->valid()); + + // test with IteratorAggregate + $it = new TestIterator([1, 2]); + $ia = new TestIteratorAggregate($it); + + $countConstraint = new Count(2); + $countConstraint->evaluate($ia, returnResult: true); + $this->assertSame(1, $it->current()); + + $it->next(); + $countConstraint->evaluate($ia, returnResult: true); + $this->assertSame(2, $it->current()); + + $it->next(); + $countConstraint->evaluate($ia, returnResult: true); + $this->assertFalse($it->valid()); + + // test with nested IteratorAggregate + $it = new TestIterator([1, 2]); + $ia = new TestIteratorAggregate($it); + $ia2 = new TestIteratorAggregate2($ia); + + $countConstraint = new Count(2); + $countConstraint->evaluate($ia2, returnResult: true); + $this->assertSame(1, $it->current()); + + $it->next(); + $countConstraint->evaluate($ia2, returnResult: true); + $this->assertSame(2, $it->current()); + + $it->next(); + $countConstraint->evaluate($ia2, returnResult: true); + $this->assertFalse($it->valid()); + } + + public function testDoesNotAcceptGenerators(): void + { + $constraint = new Count(0); + + $this->expectException(GeneratorNotSupportedException::class); + + $constraint->evaluate($this->generator()); + } + + public function testWrapsExceptionFromIteratorAggregate(): void + { + $constraint = new Count(0); + + $this->expectException(Exception::class); + + $constraint->evaluate(new ExceptionThrowingIteratorAggregate); + } + + private function generator(): Generator + { + yield 1; + } +} diff --git a/tests/unit/Framework/Constraint/Cardinality/GreaterThanTest.php b/tests/unit/Framework/Constraint/Cardinality/GreaterThanTest.php new file mode 100644 index 00000000000..9a6f287fbd7 --- /dev/null +++ b/tests/unit/Framework/Constraint/Cardinality/GreaterThanTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(GreaterThan::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class GreaterThanTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 0, + 1, + ], + + [ + false, + 'Failed asserting that 0 is greater than 1.', + 1, + 0, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $expected, mixed $actual): void + { + $constraint = new GreaterThan($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is greater than 0', new GreaterThan(0)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new GreaterThan(1))); + } +} diff --git a/tests/unit/Framework/Constraint/Cardinality/IsEmptyTest.php b/tests/unit/Framework/Constraint/Cardinality/IsEmptyTest.php new file mode 100644 index 00000000000..a1c2b932a78 --- /dev/null +++ b/tests/unit/Framework/Constraint/Cardinality/IsEmptyTest.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use ArrayIterator; +use ArrayObject; +use EmptyIterator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsEmpty::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsEmptyTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + [], + ], + + [ + true, + '', + new EmptyIterator, + ], + + [ + true, + '', + new ArrayObject, + ], + + [ + true, + '', + new ArrayIterator([]), + ], + + [ + false, + 'Failed asserting that an array is empty.', + [0], + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $actual): void + { + $constraint = new IsEmpty; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is empty', (new IsEmpty)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, new IsEmpty); + } +} diff --git a/tests/unit/Framework/Constraint/Cardinality/LessThanTest.php b/tests/unit/Framework/Constraint/Cardinality/LessThanTest.php new file mode 100644 index 00000000000..c14e962744b --- /dev/null +++ b/tests/unit/Framework/Constraint/Cardinality/LessThanTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LessThan::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class LessThanTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 1, + 0, + ], + + [ + false, + 'Failed asserting that 1 is less than 0.', + 0, + 1, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $expected, mixed $actual): void + { + $constraint = new LessThan($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is less than 0', new LessThan(0)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new LessThan(1))); + } +} diff --git a/tests/unit/Framework/Constraint/Cardinality/SameSizeTest.php b/tests/unit/Framework/Constraint/Cardinality/SameSizeTest.php new file mode 100644 index 00000000000..f11e53f7428 --- /dev/null +++ b/tests/unit/Framework/Constraint/Cardinality/SameSizeTest.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(SameSize::class)] +#[CoversClass(Count::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class SameSizeTest extends TestCase +{ + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('count matches 0', new SameSize([])->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new SameSize([]))); + } +} diff --git a/tests/unit/Framework/Constraint/Equality/IsEqualCanonicalizingTest.php b/tests/unit/Framework/Constraint/Equality/IsEqualCanonicalizingTest.php new file mode 100644 index 00000000000..72ba288bb35 --- /dev/null +++ b/tests/unit/Framework/Constraint/Equality/IsEqualCanonicalizingTest.php @@ -0,0 +1,331 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const PHP_EOL; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsEqualCanonicalizing::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsEqualCanonicalizingTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + '', + '', + ['value'], + ['value'], + ], + + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', + 1 => 'another-value', +] +EOT, + '', + '', + ['value', 'another-value'], + ['another-value', 'value'], + ], + + [ + true, + <<<'EOT' +is equal to stdClass Object #%d ( + 'foo' => 'bar', +) +EOT, + '', + '', + self::stdClass('foo', 'bar'), + self::stdClass('foo', 'bar'), + ], + + [ + true, + 'is equal to true', + '', + '', + true, + true, + ], + + [ + true, + 'is equal to true', + '', + '', + true, + 'true', + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1.0, + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1.0, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + '1', + ], + + [ + true, + 'is equal to \'1\'', + '', + '', + '1', + 1, + ], + + [ + true, + 'is equal to \'string\'', + '', + '', + 'string', + 'string', + ], + + [ + true, + 'is equal to ', + '', + '', + 'string' . PHP_EOL . 'string', + 'string' . PHP_EOL . 'string', + ], + + [ + false, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + 'Failed asserting that two arrays are equal.', + <<<'EOT' +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 'value' ++ 0 => 'another-value' + ) + +EOT, + ['value'], + ['another-value'], + ], + + [ + false, + <<<'EOT' +is equal to stdClass Object #%d ( + 'foo' => 'bar', +) +EOT, + 'Failed asserting that two objects are equal.', + <<<'EOT' +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 0 => 'bar' ++ 0 => 'foo' + ) + +EOT, + self::stdClass('foo', 'bar'), + self::stdClass('bar', 'foo'), + ], + + [ + false, + 'is equal to true', + 'Failed asserting that false matches expected true.', + 'Failed asserting that false matches expected true.', + true, + false, + ], + + [ + false, + 'is equal to 1.0', + 'Failed asserting that 1.01 matches expected 1.0.', + 'Failed asserting that 1.01 matches expected 1.0.', + 1.0, + 1.01, + ], + + [ + false, + 'is equal to 1.01', + 'Failed asserting that 1 matches expected 1.01.', + 'Failed asserting that 1 matches expected 1.01.', + 1.01, + 1, + ], + + [ + false, + 'is equal to 1', + 'Failed asserting that \'2\' matches expected 1.', + 'Failed asserting that \'2\' matches expected 1.', + 1, + '2', + ], + + [ + false, + 'is equal to \'1\'', + 'Failed asserting that 2 matches expected \'1\'.', + 'Failed asserting that 2 matches expected \'1\'.', + '1', + 2, + ], + + [ + false, + 'is equal to \'string\'', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string' ++'another-string' + +EOT, + 'string', + 'another-string', + ], + + [ + false, + 'is equal to ', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string\n +-string' ++'another-string\n ++another-string' + +EOT, + "string\nstring", + "another-string\nanother-string", + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqualCanonicalizing($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqualCanonicalizing($expected); + + $this->assertStringMatchesFormat($constraintAsString, $constraint->toString(true)); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsEqualCanonicalizing(true))); + } + + private static function stdClass(string $key, string $value): stdClass + { + $o = new stdClass; + + $o->{$key} = $value; + + return $o; + } +} diff --git a/tests/unit/Framework/Constraint/Equality/IsEqualIgnoringCaseTest.php b/tests/unit/Framework/Constraint/Equality/IsEqualIgnoringCaseTest.php new file mode 100644 index 00000000000..bb09d49f9c5 --- /dev/null +++ b/tests/unit/Framework/Constraint/Equality/IsEqualIgnoringCaseTest.php @@ -0,0 +1,308 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const PHP_EOL; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsEqualIgnoringCase::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsEqualIgnoringCaseTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + '', + '', + ['value'], + ['VALUE'], + ], + + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', + 1 => 'another-value', +] +EOT, + '', + '', + ['value', 'another-value'], + ['VALUE', 'ANOTHER-VALUE'], + ], + + [ + true, + <<<'EOT' +is equal to stdClass Object #%d ( + 'foo' => 'bar', +) +EOT, + '', + '', + self::stdClass('foo', 'bar'), + self::stdClass('foo', 'BAR'), + ], + + [ + true, + 'is equal to true', + '', + '', + true, + true, + ], + + [ + true, + 'is equal to true', + '', + '', + true, + 'true', + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1.0, + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1.0, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + '1', + ], + + [ + true, + 'is equal to \'1\'', + '', + '', + '1', + 1, + ], + + [ + true, + 'is equal to \'string\'', + '', + '', + 'string', + 'STRING', + ], + + [ + true, + 'is equal to ', + '', + '', + 'string' . PHP_EOL . 'string', + 'STRING' . PHP_EOL . 'STRING', + ], + + [ + false, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + 'Failed asserting that two arrays are equal.', + <<<'EOT' +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 'value' ++ 0 => 'another-value' + ) + +EOT, + ['value'], + ['another-value'], + ], + + [ + false, + 'is equal to true', + 'Failed asserting that false matches expected true.', + 'Failed asserting that false matches expected true.', + true, + false, + ], + + [ + false, + 'is equal to 1.0', + 'Failed asserting that 1.01 matches expected 1.0.', + 'Failed asserting that 1.01 matches expected 1.0.', + 1.0, + 1.01, + ], + + [ + false, + 'is equal to 1.01', + 'Failed asserting that 1 matches expected 1.01.', + 'Failed asserting that 1 matches expected 1.01.', + 1.01, + 1, + ], + + [ + false, + 'is equal to 1', + 'Failed asserting that \'2\' matches expected 1.', + 'Failed asserting that \'2\' matches expected 1.', + 1, + '2', + ], + + [ + false, + 'is equal to \'1\'', + 'Failed asserting that 2 matches expected \'1\'.', + 'Failed asserting that 2 matches expected \'1\'.', + '1', + 2, + ], + + [ + false, + 'is equal to \'string\'', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string' ++'another-string' + +EOT, + 'string', + 'another-string', + ], + + [ + false, + 'is equal to ', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string\n +-string' ++'another-string\n ++another-string' + +EOT, + "string\nstring", + "another-string\nanother-string", + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqualIgnoringCase($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqualIgnoringCase($expected); + + $this->assertStringMatchesFormat($constraintAsString, $constraint->toString(true)); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsEqualIgnoringCase(true))); + } + + private static function stdClass(string $key, string $value): stdClass + { + $o = new stdClass; + + $o->{$key} = $value; + + return $o; + } +} diff --git a/tests/unit/Framework/Constraint/Equality/IsEqualTest.php b/tests/unit/Framework/Constraint/Equality/IsEqualTest.php new file mode 100644 index 00000000000..82f5b8f20d9 --- /dev/null +++ b/tests/unit/Framework/Constraint/Equality/IsEqualTest.php @@ -0,0 +1,400 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const PHP_EOL; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\EnumerationEquals\Example; +use PHPUnit\TestFixture\EnumerationEquals\ExampleInt; +use PHPUnit\TestFixture\EnumerationEquals\ExampleString; +use stdClass; + +#[CoversClass(IsEqual::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsEqualTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + '', + '', + ['value'], + ['value'], + ], + + [ + true, + <<<'EOT' +is equal to stdClass Object #%d ( + 'foo' => 'bar', +) +EOT, + '', + '', + self::stdClass('foo', 'bar'), + self::stdClass('foo', 'bar'), + ], + + [ + true, + 'is equal to true', + '', + '', + true, + true, + ], + + [ + true, + 'is equal to true', + '', + '', + true, + 'true', + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1.0, + ], + + [ + true, + 'is equal to 1.0', + '', + '', + 1.0, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + 1.0, + ], + + [ + true, + 'is equal to 1', + '', + '', + 1, + '1', + ], + + [ + true, + 'is equal to \'1\'', + '', + '', + '1', + 1, + ], + + [ + true, + 'is equal to \'string\'', + '', + '', + 'string', + 'string', + ], + + [ + true, + 'is equal to ', + '', + '', + 'string' . PHP_EOL . 'string', + 'string' . PHP_EOL . 'string', + ], + + [ + true, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\Example Enum %s (Foo)', + '', + '', + Example::Foo, + Example::Foo, + ], + + [ + true, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\ExampleString Enum %s (Foo, \'foo\')', + '', + '', + ExampleString::Foo, + ExampleString::Foo, + ], + + [ + true, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\ExampleInt Enum %s (Foo, 0)', + '', + '', + ExampleInt::Foo, + ExampleInt::Foo, + ], + + [ + false, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', +] +EOT, + 'Failed asserting that two arrays are equal.', + <<<'EOT' +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 'value' ++ 0 => 'another-value' + ) + +EOT, + ['value'], + ['another-value'], + ], + + [ + false, + <<<'EOT' +is equal to Array &%d [ + 0 => 'value', + 1 => 'another-value', +] +EOT, + 'Failed asserting that two arrays are equal.', + <<<'EOT' +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 'value' +- 1 => 'another-value' ++ 0 => 'another-value' ++ 1 => 'value' + ) + +EOT, + ['value', 'another-value'], + ['another-value', 'value'], + ], + + [ + false, + <<<'EOT' +is equal to stdClass Object #%d ( + 'foo' => 'bar', +) +EOT, + 'Failed asserting that two objects are equal.', + <<<'EOT' +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 'foo' => 'bar' ++ 'bar' => 'foo' + ) + +EOT, + self::stdClass('foo', 'bar'), + self::stdClass('bar', 'foo'), + ], + + [ + false, + 'is equal to true', + 'Failed asserting that false matches expected true.', + 'Failed asserting that false matches expected true.', + true, + false, + ], + + [ + false, + 'is equal to 1.0', + 'Failed asserting that 1.01 matches expected 1.0.', + 'Failed asserting that 1.01 matches expected 1.0.', + 1.0, + 1.01, + ], + + [ + false, + 'is equal to 1.01', + 'Failed asserting that 1 matches expected 1.01.', + 'Failed asserting that 1 matches expected 1.01.', + 1.01, + 1, + ], + + [ + false, + 'is equal to 1', + 'Failed asserting that \'2\' matches expected 1.', + 'Failed asserting that \'2\' matches expected 1.', + 1, + '2', + ], + + [ + false, + 'is equal to \'1\'', + 'Failed asserting that 2 matches expected \'1\'.', + 'Failed asserting that 2 matches expected \'1\'.', + '1', + 2, + ], + + [ + false, + 'is equal to \'string\'', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string' ++'another-string' + +EOT, + 'string', + 'another-string', + ], + + [ + false, + 'is equal to ', + 'Failed asserting that two strings are equal.', + <<<'EOT' +Failed asserting that two strings are equal. +--- Expected ++++ Actual +@@ @@ +-'string\n +-string' ++'another-string\n ++another-string' + +EOT, + "string\nstring", + "another-string\nanother-string", + ], + + [ + false, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\Example Enum %s (Foo)', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\Example are equal, Bar does not match expected Foo.', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\Example are equal, Bar does not match expected Foo.', + Example::Foo, + Example::Bar, + ], + + [ + false, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\ExampleString Enum %s (Foo, \'foo\')', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\ExampleString are equal, Bar does not match expected Foo.', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\ExampleString are equal, Bar does not match expected Foo.', + ExampleString::Foo, + ExampleString::Bar, + ], + + [ + false, + 'is equal to PHPUnit\TestFixture\EnumerationEquals\ExampleInt Enum %s (Foo, 0)', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\ExampleInt are equal, Bar does not match expected Foo.', + 'Failed asserting that two values of enumeration PHPUnit\TestFixture\EnumerationEquals\ExampleInt are equal, Bar does not match expected Foo.', + ExampleInt::Foo, + ExampleInt::Bar, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqual($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsEqual($expected); + + $this->assertStringMatchesFormat($constraintAsString, $constraint->toString(true)); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsEqual(true))); + } + + private static function stdClass(string $key, string $value): stdClass + { + $o = new stdClass; + + $o->{$key} = $value; + + return $o; + } +} diff --git a/tests/unit/Framework/Constraint/Equality/IsEqualWithDeltaTest.php b/tests/unit/Framework/Constraint/Equality/IsEqualWithDeltaTest.php new file mode 100644 index 00000000000..6d7ef6917a7 --- /dev/null +++ b/tests/unit/Framework/Constraint/Equality/IsEqualWithDeltaTest.php @@ -0,0 +1,207 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsEqualWithDelta::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsEqualWithDeltaTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + 'is equal to 1.0 with delta <0.000000>', + '', + '', + 1.0, + 0.0, + 1.0, + ], + + [ + true, + 'is equal to 1.0 with delta <0.100000>', + '', + '', + 1.0, + 0.1, + 1.09, + ], + + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 1.0, +] with delta <0.000000> +EOT, + '', + '', + [1.0], + 0.0, + [1.0], + ], + + [ + true, + <<<'EOT' +is equal to Array &%d [ + 0 => 1.0, +] with delta <0.100000> +EOT, + '', + '', + [1.0], + 0.1, + [1.09], + ], + + [ + true, + <<<'EOT' +is equal to stdClass Object #%d ( + 'property' => 1.0, +) with delta <0.000000> +EOT, + '', + '', + self::stdClass('property', 1.0), + 0.0, + self::stdClass('property', 1.0), + ], + + [ + true, + <<<'EOT' +is equal to stdClass Object #%d ( + 'property' => 1.0, +) with delta <0.100000> +EOT, + '', + '', + self::stdClass('property', 1.0), + 0.1, + self::stdClass('property', 1.09), + ], + + [ + false, + 'is equal to 1.0 with delta <0.100000>', + 'Failed asserting that 1.1 matches expected 1.0.', + 'Failed asserting that 1.1 matches expected 1.0.', + 1.0, + 0.1, + 1.1, + ], + + [ + false, + <<<'EOT' +is equal to Array &%d [ + 0 => 1.0, +] with delta <0.000000> +EOT, + 'Failed asserting that two arrays are equal.', + <<<'EOT' +Failed asserting that two arrays are equal. +--- Expected ++++ Actual +@@ @@ + Array ( +- 0 => 1.0 ++ 0 => 1.01 + ) + +EOT, + [1.0], + 0.0, + [1.01], + ], + + [ + false, + <<<'EOT' +is equal to stdClass Object #%d ( + 'property' => 1.0, +) with delta <0.000000> +EOT, + 'Failed asserting that two objects are equal.', + <<<'EOT' +Failed asserting that two objects are equal. +--- Expected ++++ Actual +@@ @@ + stdClass Object ( +- 'property' => 1.0 ++ 'property' => 1.01 + ) + +EOT, + self::stdClass('property', 1.0), + 0.0, + self::stdClass('property', 1.01), + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, float $delta, mixed $actual): void + { + $constraint = new IsEqualWithDelta($expected, $delta); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, float $delta, mixed $actual): void + { + $constraint = new IsEqualWithDelta($expected, $delta); + + $this->assertStringMatchesFormat($constraintAsString, $constraint->toString(true)); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsEqualWithDelta(1.0, 0.0))); + } + + private static function stdClass(string $key, float $value): stdClass + { + $o = new stdClass; + + $o->{$key} = $value; + + return $o; + } +} diff --git a/tests/unit/Framework/Constraint/Exception/ExceptionCodeTest.php b/tests/unit/Framework/Constraint/Exception/ExceptionCodeTest.php new file mode 100644 index 00000000000..1fd4922e291 --- /dev/null +++ b/tests/unit/Framework/Constraint/Exception/ExceptionCodeTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExceptionCode::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class ExceptionCodeTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 1234, + 1234, + ], + + [ + false, + 'Failed asserting that 4567 is equal to expected exception code 1234.', + 1234, + 4567, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, int $expected, mixed $actual): void + { + $constraint = new ExceptionCode($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('exception code is 1234', new ExceptionCode(1234)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new ExceptionCode(1234))); + } +} diff --git a/tests/unit/Framework/Constraint/Exception/ExceptionMessageIsOrContainsTest.php b/tests/unit/Framework/Constraint/Exception/ExceptionMessageIsOrContainsTest.php new file mode 100644 index 00000000000..44bfc7db747 --- /dev/null +++ b/tests/unit/Framework/Constraint/Exception/ExceptionMessageIsOrContainsTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExceptionMessageIsOrContains::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class ExceptionMessageIsOrContainsTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 'expected-message', + 'expected-message', + ], + + [ + true, + '', + '', + '', + ], + + [ + false, + 'Failed asserting that exception message is empty but is \'actual-message\'.', + '', + 'actual-message', + ], + + [ + false, + 'Failed asserting that exception message \'actual-message\' contains \'expected-message\'.', + 'expected-message', + 'actual-message', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, mixed $actual): void + { + $constraint = new ExceptionMessageIsOrContains($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('exception message contains \'message\'', new ExceptionMessageIsOrContains('message')->toString()); + $this->assertSame('exception message is empty', new ExceptionMessageIsOrContains('')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new ExceptionMessageIsOrContains('message'))); + } +} diff --git a/tests/unit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpressionTest.php b/tests/unit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpressionTest.php new file mode 100644 index 00000000000..6b5668c6456 --- /dev/null +++ b/tests/unit/Framework/Constraint/Exception/ExceptionMessageMatchesRegularExpressionTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Exception; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExceptionMessageMatchesRegularExpression::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class ExceptionMessageMatchesRegularExpressionTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + '/[0-9]/', + '1234', + ], + + [ + false, + 'Failed asserting that exception message \'abcd\' matches \'/[0-9]/\'.', + '/[0-9]/', + 'abcd', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, mixed $actual): void + { + $constraint = new ExceptionMessageMatchesRegularExpression($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testRejectsInvalidRegularExpression(): void + { + $constraint = new ExceptionMessageMatchesRegularExpression('invalid regular expression'); + + $this->expectException(Exception::class); + $this->expectExceptionMessage('Invalid expected exception message regular expression given: invalid regular expression'); + + $constraint->evaluate('abcd'); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('exception message matches \'/.*/\'', new ExceptionMessageMatchesRegularExpression('/.*/')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new ExceptionMessageMatchesRegularExpression('/.*/'))); + } +} diff --git a/tests/unit/Framework/Constraint/Exception/ExceptionTest.php b/tests/unit/Framework/Constraint/Exception/ExceptionTest.php new file mode 100644 index 00000000000..2b8d7895d41 --- /dev/null +++ b/tests/unit/Framework/Constraint/Exception/ExceptionTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use InvalidArgumentException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use RuntimeException; + +#[CoversClass(Exception::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class ExceptionTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + RuntimeException::class, + new RuntimeException, + ], + + [ + false, + 'Failed asserting that exception of type "RuntimeException" is thrown.', + RuntimeException::class, + null, + ], + + [ + false, + 'Failed asserting that exception of type "InvalidArgumentException" matches expected exception "RuntimeException". Message was: "message" at', + RuntimeException::class, + new InvalidArgumentException('message'), + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, mixed $actual): void + { + $constraint = new Exception($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('exception of type "Exception"', new Exception(\Exception::class)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new Exception(\Exception::class))); + } +} diff --git a/tests/unit/Framework/Constraint/Filesystem/DirectoryExistsTest.php b/tests/unit/Framework/Constraint/Filesystem/DirectoryExistsTest.php new file mode 100644 index 00000000000..9734f29d1bd --- /dev/null +++ b/tests/unit/Framework/Constraint/Filesystem/DirectoryExistsTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(DirectoryExists::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class DirectoryExistsTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + __DIR__, + ], + + [ + false, + 'Failed asserting that directory "/does/not/exist" exists.', + '/does/not/exist', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $actual): void + { + $constraint = new DirectoryExists; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('directory exists', (new DirectoryExists)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new DirectoryExists)); + } +} diff --git a/tests/unit/Framework/Constraint/Filesystem/FileExistsTest.php b/tests/unit/Framework/Constraint/Filesystem/FileExistsTest.php new file mode 100644 index 00000000000..a6e5b977565 --- /dev/null +++ b/tests/unit/Framework/Constraint/Filesystem/FileExistsTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(FileExists::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class FileExistsTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + __FILE__, + ], + + [ + false, + 'Failed asserting that file "/does/not/exist" exists.', + '/does/not/exist', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $actual): void + { + $constraint = new FileExists; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('file exists', (new FileExists)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new FileExists)); + } +} diff --git a/tests/unit/Framework/Constraint/Filesystem/IsReadableTest.php b/tests/unit/Framework/Constraint/Filesystem/IsReadableTest.php new file mode 100644 index 00000000000..6c73081caf6 --- /dev/null +++ b/tests/unit/Framework/Constraint/Filesystem/IsReadableTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsReadable::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsReadableTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + __FILE__, + ], + + [ + false, + 'Failed asserting that "/is/not/readable" is readable.', + '/is/not/readable', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $actual): void + { + $constraint = new IsReadable; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is readable', (new IsReadable)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsReadable)); + } +} diff --git a/tests/unit/Framework/Constraint/Filesystem/IsWritableTest.php b/tests/unit/Framework/Constraint/Filesystem/IsWritableTest.php new file mode 100644 index 00000000000..b042ec448d5 --- /dev/null +++ b/tests/unit/Framework/Constraint/Filesystem/IsWritableTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsWritable::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsWritableTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + __FILE__, + ], + + [ + false, + 'Failed asserting that "/is/not/writable" is writable.', + '/is/not/writable', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $actual): void + { + $constraint = new IsWritable; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is writable', (new IsWritable)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsWritable)); + } +} diff --git a/tests/unit/Framework/Constraint/IsAnythingTest.php b/tests/unit/Framework/Constraint/IsAnythingTest.php new file mode 100644 index 00000000000..daa5ffc0020 --- /dev/null +++ b/tests/unit/Framework/Constraint/IsAnythingTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsAnything::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsAnythingTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $this->assertTrue((new IsAnything)->evaluate(true, returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is anything', (new IsAnything)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(0, (new IsAnything)); + } +} diff --git a/tests/unit/Framework/Constraint/IsIdenticalTest.php b/tests/unit/Framework/Constraint/IsIdenticalTest.php new file mode 100644 index 00000000000..a77e655ed40 --- /dev/null +++ b/tests/unit/Framework/Constraint/IsIdenticalTest.php @@ -0,0 +1,182 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsIdentical::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsIdenticalTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + 'is identical to 0', + 'Failed asserting that 1 is identical to 0.', + '', + 0, + 1, + ], + + [ + 'is identical to an object of class "stdClass"', + 'Failed asserting that two variables reference the same object.', + '', + new stdClass, + new stdClass, + ], + + [ + 'is identical to \'expected\'', + 'Failed asserting that two strings are identical.', + <<<'EOT' + +--- Expected ++++ Actual +@@ @@ +-'expected' ++'actual' + +EOT, + 'expected', + 'actual', + ], + + [ + <<<'EOT' +is identical to Array &0 [ + 0 => 1, + 1 => 2, + 2 => 3, + 3 => 4, + 4 => 5, + 5 => 6, +] +EOT, + 'Failed asserting that two arrays are identical.', + <<<'EOT' + +--- Expected ++++ Actual +@@ @@ + Array &0 [ + 0 => 1, + 1 => 2, +- 2 => 3, ++ 2 => 33, + 3 => 4, + 4 => 5, + 5 => 6, + ] + +EOT, + [1, 2, 3, 4, 5, 6], + [1, 2, 33, 4, 5, 6], + ], + + [ + <<<'EOT' +is identical to Array &0 [ + 0 => Array &1 [ + 'A' => 'B', + ], + 1 => Array &2 [ + 'C' => Array &3 [ + 0 => 'D', + 1 => 'E', + ], + ], +] +EOT, + 'Failed asserting that two arrays are identical.', + <<<'EOT' + +--- Expected ++++ Actual +@@ @@ + Array &0 [ + 0 => Array &1 [ +- 'A' => 'B', ++ 'A' => 'C', + ], + 1 => Array &2 [ + 'C' => Array &3 [ +- 0 => 'D', ++ 0 => 'C', + 1 => 'E', ++ 2 => 'F', + ], + ], + ] + +EOT, + [ + ['A' => 'B'], + [ + 'C' => [ + 'D', + 'E', + ], + ], + ], + [ + ['A' => 'C'], + [ + 'C' => [ + 'C', + 'E', + 'F', + ], + ], + ], + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsIdentical($expected); + + $this->assertTrue($constraint->evaluate($expected, returnResult: true)); + $this->assertFalse($constraint->evaluate($actual, returnResult: true)); + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(string $constraintAsString, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new IsIdentical($expected); + + $this->assertSame($constraintAsString, $constraint->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsIdentical(true))); + } +} diff --git a/tests/unit/Framework/Constraint/JsonMatchesTest.php b/tests/unit/Framework/Constraint/JsonMatchesTest.php new file mode 100644 index 00000000000..adbab49aead --- /dev/null +++ b/tests/unit/Framework/Constraint/JsonMatchesTest.php @@ -0,0 +1,418 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function json_encode; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(JsonMatches::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class JsonMatchesTest extends TestCase +{ + public static function provider(): array + { + return [ + 'valid JSON' => [ + true, + '', + '', + json_encode(['Mascott' => 'Tux']), + json_encode(['Mascott' => 'Tux']), + ], + + 'object fields are unordered' => [ + true, + '', + '', + '{"second":"2", "first":1}', + '{"first":1, "second":"2"}', + ], + + 'object fields with numeric keys are unordered' => [ + true, + '', + '', + '{"0":null,"a":{},"b":[],"c":"1","d":1,"e":-1,"f":[1,2],"g":[2,1],"h":{"0":"0","1":"1","2":"2"}}', + '{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}', + ], + + 'child object fields are unordered' => [ + true, + '', + '', + '{"Mascott": {"age":5, "name":"Tux"}}', + '{"Mascott": {"name":"Tux", "age":5}}', + ], + + 'single boolean valid json' => [ + true, + '', + '', + 'true', + 'true', + ], + + 'single number valid json' => [ + true, + '', + '', + '5.3', + '5.3', + ], + + 'single null valid json' => [ + true, + '', + '', + 'null', + 'null', + ], + + 'invalid JSON in class instantiation' => [ + false, + 'Failed asserting that \'{"Mascott":"Tux"}\' matches JSON string "{"Mascott"::}".', + '', + '{"Mascott"::}', + json_encode(['Mascott' => 'Tux']), + ], + + 'error syntax' => [ + false, + 'Failed asserting that \'{"Mascott"::}\' matches JSON string "{"Mascott":"Tux"}".', + '', + json_encode(['Mascott' => 'Tux']), + '{"Mascott"::}', + ], + + 'error UTF-8' => [ + false, + 'Failed asserting that \'' . json_encode('\xB1\x31') . '\' matches JSON string "{"Mascott":"Tux"}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ +-{ +- "Mascott": "Tux" +-} ++"\\xB1\\x31" + +EOT, + json_encode(['Mascott' => 'Tux']), + json_encode('\xB1\x31'), + ], + + 'string type not equals number' => [ + false, + 'Failed asserting that \'{"age": "5"}\' matches JSON string "{"age": 5}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + { +- "age": 5 ++ "age": "5" + } + +EOT, + '{"age": 5}', + '{"age": "5"}', + ], + + 'string type not equals boolean' => [ + false, + 'Failed asserting that \'{"age": "true"}\' matches JSON string "{"age": true}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + { +- "age": true ++ "age": "true" + } + +EOT, + '{"age": true}', + '{"age": "true"}', + ], + + 'string type not equals null' => [ + false, + 'Failed asserting that \'{"age": "null"}\' matches JSON string "{"age": null}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + { +- "age": null ++ "age": "null" + } + +EOT, + '{"age": null}', + '{"age": "null"}', + ], + + 'null field different from missing field' => [ + false, + 'Failed asserting that \'{"present": true, "missing": null}\' matches JSON string "{"present": true}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + { ++ "missing": null, + "present": true + } + +EOT, + '{"present": true}', + '{"present": true, "missing": null}', + ], + + 'array elements are ordered' => [ + false, + 'Failed asserting that \'["first", "second"]\' matches JSON string "["second", "first"]".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + [ +- "second", +- "first" ++ "first", ++ "second" + ] + +EOT, + '["second", "first"]', + '["first", "second"]', + ], + + 'objects with numeric keys are not arrays' => [ + false, + 'Failed asserting that \'[{}]\' matches JSON string "{"0":{}}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ +-{ +- "0": {} +-} ++[ ++ {} ++] + +EOT, + '{"0":{}}', + '[{}]', + ], + + 'child array elements are ordered' => [ + false, + 'Failed asserting that \'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[2,1],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}\' matches JSON string "{"0":null,"a":{},"b":[],"c":"1","d":1,"e":-1,"f":[1,2],"g":[2,1],"h":{"0":"0","1":"1","2":"2"}}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + "d": 1, + "e": -1, + "f": [ +- 1, +- 2 ++ 2, ++ 1 + ], + "g": [ + 2, + +EOT, + '{"0":null,"a":{},"b":[],"c":"1","d":1,"e":-1,"f":[1,2],"g":[2,1],"h":{"0":"0","1":"1","2":"2"}}', + '{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[2,1],"h":{"2":"2","1":"1","0":"0"},"g":[2,1]}', + ], + + 'child object with numeric fields stay as object' => [ + false, + 'Failed asserting that \'{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":["0","1","2"],"g":[2,1]}\' matches JSON string "{"0":null,"a":{},"b":[],"c":"1","d":1,"e":-1,"f":[1,2],"g":[2,1],"h":{"0":"0","1":"1","2":"2"}}".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + 2, + 1 + ], +- "h": { +- "0": "0", +- "1": "1", +- "2": "2" +- } ++ "h": [ ++ "0", ++ "1", ++ "2" ++ ] + } + +EOT, + '{"0":null,"a":{},"b":[],"c":"1","d":1,"e":-1,"f":[1,2],"g":[2,1],"h":{"0":"0","1":"1","2":"2"}}', + '{"a":{},"d":1,"b":[],"e":-1,"0":null,"c":"1","f":[1,2],"h":["0","1","2"],"g":[2,1]}', + ], + + 'nested arrays are ordered' => [ + false, + 'Failed asserting that \'[{"1":"1","0":"0"},{"2":"2","3":"3"}]\' matches JSON string "[[1,0],[2,3]]".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + [ +- [ +- 1, +- 0 +- ], +- [ +- 2, +- 3 +- ] ++ { ++ "0": "0", ++ "1": "1" ++ }, ++ { ++ "2": "2", ++ "3": "3" ++ } + ] + +EOT, + '[[1,0],[2,3]]', + '[{"1":"1","0":"0"},{"2":"2","3":"3"}]', + ], + + 'child objects in arrays stay in order' => [ + false, + 'Failed asserting that \'[{"2":"2","3":"3"},{"1":"1","0":"0"}]\' matches JSON string "[{"0":"0","1":"1"},{"2":"2","3":"3"}]".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ + [ + { ++ "2": "2", ++ "3": "3" ++ }, ++ { + "0": "0", + "1": "1" +- }, +- { +- "2": "2", +- "3": "3" + } + ] + +EOT, + + '[{"0":"0","1":"1"},{"2":"2","3":"3"}]', + '[{"2":"2","3":"3"},{"1":"1","0":"0"}]', + ], + + 'objects are not arrays' => [ + false, + 'Failed asserting that \'{}\' matches JSON string "[]".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ +-[] ++{} + +EOT, + '[]', + '{}', + ], + + 'arrays are not objects' => [ + false, + 'Failed asserting that \'{}\' matches JSON string "[]".', + <<<'EOT' +Failed asserting that two json values are equal. +--- Expected ++++ Actual +@@ @@ +-[] ++{} + +EOT, + '[]', + '{}', + ], + + 'objects in arrays are unordered' => [ + true, + '', + '', + '[{"0":"0","1":"1"},{"2":"2","3":"3"}]', + '[{"1":"1","0":"0"},{"2":"2","3":"3"}]', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $comparisonFailureAsString, mixed $expected, mixed $actual): void + { + $constraint = new JsonMatches($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + try { + $constraint->evaluate($actual); + } catch (ExpectationFailedException $e) { + $this->assertSame($failureDescription, $e->getMessage()); + $this->assertSame($comparisonFailureAsString, $e->getComparisonFailure() ? $e->getComparisonFailure()->toString() : ''); + + return; + } + + $this->fail(); + } + + public function testCanBeRepresentedAsString(): void + { + $constraint = new JsonMatches(json_encode(['key' => 'value'])); + + $this->assertSame('matches JSON string "{"key":"value"}"', $constraint->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new JsonMatches(json_encode(['key' => 'value'])))); + } +} diff --git a/tests/unit/Framework/Constraint/Math/IsFiniteTest.php b/tests/unit/Framework/Constraint/Math/IsFiniteTest.php new file mode 100644 index 00000000000..1371d30ea5b --- /dev/null +++ b/tests/unit/Framework/Constraint/Math/IsFiniteTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function acos; +use function log; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsFinite::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsFiniteTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $constraint = new IsFinite; + + $this->assertTrue($constraint->evaluate(1, returnResult: true)); + $this->assertFalse($constraint->evaluate(log(0), returnResult: true)); + $this->assertFalse($constraint->evaluate(acos(2), returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is finite', (new IsFinite)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsFinite)); + } +} diff --git a/tests/unit/Framework/Constraint/Math/IsInfiniteTest.php b/tests/unit/Framework/Constraint/Math/IsInfiniteTest.php new file mode 100644 index 00000000000..9b891c32071 --- /dev/null +++ b/tests/unit/Framework/Constraint/Math/IsInfiniteTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function acos; +use function log; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsInfinite::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsInfiniteTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $constraint = new IsInfinite; + + $this->assertTrue($constraint->evaluate(log(0), returnResult: true)); + $this->assertFalse($constraint->evaluate(1, returnResult: true)); + $this->assertFalse($constraint->evaluate(acos(2), returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is infinite', (new IsInfinite)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsInfinite)); + } +} diff --git a/tests/unit/Framework/Constraint/Math/IsNanTest.php b/tests/unit/Framework/Constraint/Math/IsNanTest.php new file mode 100644 index 00000000000..d2038ebc8ea --- /dev/null +++ b/tests/unit/Framework/Constraint/Math/IsNanTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function acos; +use function log; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsNan::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsNanTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $constraint = new IsNan; + + $this->assertTrue($constraint->evaluate(acos(2), returnResult: true)); + $this->assertFalse($constraint->evaluate(log(0), returnResult: true)); + $this->assertFalse($constraint->evaluate(1, returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is nan', (new IsNan)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsNan)); + } +} diff --git a/tests/unit/Framework/Constraint/Object/ObjectEqualsTest.php b/tests/unit/Framework/Constraint/Object/ObjectEqualsTest.php new file mode 100644 index 00000000000..9d4d9f61241 --- /dev/null +++ b/tests/unit/Framework/Constraint/Object/ObjectEqualsTest.php @@ -0,0 +1,154 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\ActualValueIsNotAnObjectException; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ComparisonMethodDoesNotAcceptParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareBoolReturnTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareExactlyOneParameterException; +use PHPUnit\Framework\ComparisonMethodDoesNotDeclareParameterTypeException; +use PHPUnit\Framework\ComparisonMethodDoesNotExistException; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\ObjectEquals\ValueObject; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatAcceptsTooManyArguments; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotAcceptArguments; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasUnionParameterType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithNullableReturnType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithoutReturnType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithUnionReturnType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithVoidReturnType; +use PHPUnit\TestFixture\ObjectEquals\ValueObjectWithoutEqualsMethod; + +#[CoversClass(ObjectEquals::class)] +#[CoversClass(ActualValueIsNotAnObjectException::class)] +#[CoversClass(ComparisonMethodDoesNotExistException::class)] +#[CoversClass(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class)] +#[CoversClass(ComparisonMethodDoesNotDeclareExactlyOneParameterException::class)] +#[CoversClass(ComparisonMethodDoesNotDeclareParameterTypeException::class)] +#[CoversClass(ComparisonMethodDoesNotAcceptParameterTypeException::class)] +#[Small] +final class ObjectEqualsTest extends TestCase +{ + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('two objects are equal', new ObjectEquals(new ValueObject(1))->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new ObjectEquals(new ValueObject(1)))); + } + + public function testAcceptsActualObjectWhenMethodSaysTheyAreEqual(): void + { + $this->assertTrue(new ObjectEquals(new ValueObject(1))->evaluate(new ValueObject(1), '', true)); + } + + public function testRejectsActualValueThatIsNotAnObject(): void + { + $this->expectException(ActualValueIsNotAnObjectException::class); + $this->expectExceptionMessage('Actual value is not an object'); + + new ObjectEquals(new ValueObject(1))->evaluate(null); + } + + public function testRejectsActualObjectThatDoesNotHaveTheSpecifiedMethod(): void + { + $this->expectException(ComparisonMethodDoesNotExistException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithoutEqualsMethod::equals() does not exist.'); + + new ObjectEquals(new ValueObjectWithoutEqualsMethod(1))->evaluate(new ValueObjectWithoutEqualsMethod(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsNotDeclaredToReturnBool(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithoutReturnType::equals() does not declare bool return type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodWithoutReturnType(1))->evaluate(new ValueObjectWithEqualsMethodWithoutReturnType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredToReturnUnion(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithUnionReturnType::equals() does not declare bool return type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodWithUnionReturnType(1))->evaluate(new ValueObjectWithEqualsMethodWithUnionReturnType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredVoid(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithVoidReturnType::equals() does not declare bool return type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodWithVoidReturnType(1))->evaluate(new ValueObjectWithEqualsMethodWithVoidReturnType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodExistsButIsDeclaredNullable(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareBoolReturnTypeException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodWithNullableReturnType::equals() does not declare bool return type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodWithNullableReturnType(1))->evaluate(new ValueObjectWithEqualsMethodWithNullableReturnType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodDoesNotAcceptArguments(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareExactlyOneParameterException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotAcceptArguments::equals() does not declare exactly one parameter.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodThatDoesNotAcceptArguments(1))->evaluate(new ValueObjectWithEqualsMethodThatDoesNotAcceptArguments(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodAcceptsTooManyArguments(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareExactlyOneParameterException::class); + $this->expectExceptionMessage('Comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatAcceptsTooManyArguments::equals() does not declare exactly one parameter.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodThatAcceptsTooManyArguments(1))->evaluate(new ValueObjectWithEqualsMethodThatAcceptsTooManyArguments(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodDoesNotDeclareParameterType(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareParameterTypeException::class); + $this->expectExceptionMessage('Parameter of comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType::equals() does not have a declared type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType(1))->evaluate(new ValueObjectWithEqualsMethodThatDoesNotDeclareParameterType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodHasUnionParameterType(): void + { + $this->expectException(ComparisonMethodDoesNotDeclareParameterTypeException::class); + $this->expectExceptionMessage('Parameter of comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasUnionParameterType::equals() does not have a declared type.'); + + new ObjectEquals(new ValueObjectWithEqualsMethodThatHasUnionParameterType(1))->evaluate(new ValueObjectWithEqualsMethodThatHasUnionParameterType(1)); + } + + public function testRejectsActualObjectWhenTheSpecifiedMethodHasIncompatibleParameterType(): void + { + $this->expectException(ComparisonMethodDoesNotAcceptParameterTypeException::class); + $this->expectExceptionMessage('PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType is not an accepted argument type for comparison method PHPUnit\TestFixture\ObjectEquals\ValueObjectWithEqualsMethodThatHasIncompatibleParameterType::equals().'); + + new ObjectEquals(new ValueObjectWithEqualsMethodThatHasIncompatibleParameterType(1))->evaluate(new ValueObjectWithEqualsMethodThatHasIncompatibleParameterType(1)); + } + + public function testRejectsActualObjectWhenMethodSaysTheyAreNotEqual(): void + { + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage('Failed asserting that two objects are equal.'); + + new ObjectEquals(new ValueObject(1))->evaluate(new ValueObject(2)); + } +} diff --git a/tests/unit/Framework/Constraint/Object/ObjectHasPropertyTest.php b/tests/unit/Framework/Constraint/Object/ObjectHasPropertyTest.php new file mode 100644 index 00000000000..03344baa107 --- /dev/null +++ b/tests/unit/Framework/Constraint/Object/ObjectHasPropertyTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(ObjectHasProperty::class)] +#[Small] +final class ObjectHasPropertyTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $constraint = new ObjectHasProperty('theProperty'); + + $objectWithProperty = new stdClass; + $objectWithProperty->theProperty = 'value'; + + $this->assertTrue($constraint->evaluate($objectWithProperty, returnResult: true)); + $this->assertFalse($constraint->evaluate(new stdClass, returnResult: true)); + $this->assertFalse($constraint->evaluate(null, returnResult: true)); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage('Failed asserting that object of class "stdClass" has property "theProperty".'); + + $constraint->evaluate(new stdClass); + } + + public function testHandlesNonObjectsGracefully(): void + { + $constraint = new ObjectHasProperty('theProperty'); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage('Failed asserting that "non-object" (string) has property "theProperty".'); + + $constraint->evaluate('non-object'); + } + + public function testCanBeRepresentedAsString(): void + { + $constraint = new ObjectHasProperty('theProperty'); + + $this->assertSame('has property "theProperty"', $constraint->toString()); + } + + public function testIsCountable(): void + { + $constraint = new ObjectHasProperty('theProperty'); + + $this->assertCount(1, $constraint); + } +} diff --git a/tests/unit/Framework/Constraint/Operator/LogicalAndTest.php b/tests/unit/Framework/Constraint/Operator/LogicalAndTest.php new file mode 100644 index 00000000000..51d2421017c --- /dev/null +++ b/tests/unit/Framework/Constraint/Operator/LogicalAndTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LogicalAnd::class)] +#[CoversClass(BinaryOperator::class)] +#[CoversClass(Operator::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class LogicalAndTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + 'is of type bool and is true', + '', + self::logicalAnd( + self::isBool(), + self::isTrue(), + ), + true, + ], + + [ + true, + 'is of type bool and is equal to true', + '', + self::logicalAnd( + self::isBool(), + true, + ), + true, + ], + + [ + true, + 'is of type bool and ( is true or is false )', + '', + self::logicalAnd( + self::isBool(), + self::logicalOr( + self::isTrue(), + self::isFalse(), + ), + ), + true, + ], + + [ + false, + 'is of type bool and is true', + 'Failed asserting that false is of type bool and is true.', + self::logicalAnd( + self::isBool(), + self::isTrue(), + ), + false, + ], + + [ + false, + 'is of type bool and ( is true or is false )', + 'Failed asserting that \'string\' is of type bool and ( is true or is false ).', + self::logicalAnd( + self::isBool(), + self::logicalOr( + self::isTrue(), + self::isFalse(), + ), + ), + 'string', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, LogicalAnd $constraint, mixed $actual): void + { + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, LogicalAnd $constraint, mixed $actual): void + { + $this->assertSame($constraintAsString, $constraint->toString()); + } + + public function testIsCountable(): void + { + $constraint = $this->logicalAnd( + $this->isBool(), + true, + ); + + $this->assertCount(2, $constraint); + } +} diff --git a/tests/unit/Framework/Constraint/Operator/LogicalNotTest.php b/tests/unit/Framework/Constraint/Operator/LogicalNotTest.php new file mode 100644 index 00000000000..882f81ed799 --- /dev/null +++ b/tests/unit/Framework/Constraint/Operator/LogicalNotTest.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LogicalNot::class)] +#[CoversClass(UnaryOperator::class)] +#[CoversClass(Operator::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class LogicalNotTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + self::logicalNot(self::isTrue()), + false, + ], + + [ + false, + 'Failed asserting that true is not true.', + self::logicalNot(self::isTrue()), + true, + ], + + [ + false, + 'Failed asserting that not( true is true or is true ).', + self::logicalNot( + self::logicalOr( + self::isTrue(), + self::isTrue(), + ), + ), + true, + ], + ]; + } + + public static function negateProvider(): array + { + return [ + ['ocean contains water', 'ocean does not contain water'], + [ + '\'this is water\' contains "water" and contains "is"', + '\'this is water\' does not contain "water" and does not contain "is"', + ], + ['what it contains', 'what it contains'], + ['life exists in outer space', 'life does not exist in outer space'], + ['alien exists', 'alien does not exist'], + ['it coexists', 'it coexists'], + ['the dog has a bone', 'the dog does not have a bone'], + ['whatever it has', 'whatever it has'], + ['apple is red', 'apple is not red'], + ['yes, it is', 'yes, it is'], + ['this is clock', 'this is not clock'], + ['how are you?', 'how are not you?'], + ['how dare you!', 'how dare you!'], + ['what they are', 'what they are'], + ['that matches my preferences', 'that does not match my preferences'], + ['dinner starts with desert', 'dinner starts not with desert'], + ['it starts with', 'it starts with'], + ['dinner ends with desert', 'dinner ends not with desert'], + ['it ends with', 'it ends with'], + ['you reference me', 'you don\'t reference me'], + ['it\'s not not false', 'it\'s not false'], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, LogicalNot $constraint, mixed $actual): void + { + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + #[DataProvider('negateProvider')] + public function testCanNegateStatement(string $input, string $expected): void + { + $this->assertSame($expected, LogicalNot::negate($input)); + } + + public function testCanBeRepresentedAsString(): void + { + $constraint = $this->logicalNot( + $this->logicalOr( + $this->isTrue(), + $this->isFalse(), + ), + ); + + $this->assertSame('not( is true or is false )', $constraint->toString()); + } + + public function testIsCountable(): void + { + $constraint = $this->logicalNot( + $this->logicalOr( + $this->isTrue(), + $this->isFalse(), + ), + ); + + $this->assertCount(2, $constraint); + } + + #[TestDox('LogicalNot(IsEqual(\'test contains something\')) is handled correctly')] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/5516')] + public function testForNotEqualsWithStringThatContainsContains(): void + { + $constraint = new LogicalNot(new IsEqual('test contains something')); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage("Failed asserting that 'test contains something' is not equal to 'test contains something'."); + + Assert::assertThat('test contains something', $constraint); + } +} diff --git a/tests/unit/Framework/Constraint/Operator/LogicalOrTest.php b/tests/unit/Framework/Constraint/Operator/LogicalOrTest.php new file mode 100644 index 00000000000..48bf53166ac --- /dev/null +++ b/tests/unit/Framework/Constraint/Operator/LogicalOrTest.php @@ -0,0 +1,107 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LogicalOr::class)] +#[CoversClass(BinaryOperator::class)] +#[CoversClass(Operator::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class LogicalOrTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + 'is of type bool or is true', + '', + self::logicalOr( + self::isBool(), + self::isTrue(), + ), + true, + ], + + [ + true, + 'is of type bool or is equal to true', + '', + self::logicalOr( + self::isBool(), + true, + ), + true, + ], + + [ + true, + 'is true or is of type bool and is false', + '', + self::logicalOr( + self::isTrue(), + self::logicalAnd( + self::isBool(), + self::isFalse(), + ), + ), + true, + ], + + [ + false, + 'is of type bool or is of type string', + 'Failed asserting that 0 is of type bool or is of type string.', + self::logicalOr( + self::isBool(), + self::isString(), + ), + 0, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, LogicalOr $constraint, mixed $actual): void + { + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, LogicalOr $constraint, mixed $actual): void + { + $this->assertSame($constraintAsString, $constraint->toString()); + } + + public function testIsCountable(): void + { + $constraint = $this->logicalOr( + $this->isBool(), + true, + ); + + $this->assertCount(2, $constraint); + } +} diff --git a/tests/unit/Framework/Constraint/Operator/LogicalXorTest.php b/tests/unit/Framework/Constraint/Operator/LogicalXorTest.php new file mode 100644 index 00000000000..f9fa2dd65f6 --- /dev/null +++ b/tests/unit/Framework/Constraint/Operator/LogicalXorTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(LogicalXor::class)] +#[CoversClass(BinaryOperator::class)] +#[CoversClass(Operator::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class LogicalXorTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + 'is false xor is true', + '', + self::logicalXor( + self::isFalse(), + self::isTrue(), + ), + true, + ], + + [ + true, + 'is false xor is equal to true', + '', + self::logicalXor( + self::isFalse(), + true, + ), + true, + ], + + [ + true, + 'is of type bool xor is true', + '', + self::logicalXor( + self::isBool(), + self::isTrue(), + ), + false, + ], + + [ + false, + 'is of type bool xor is true', + 'Failed asserting that true is of type bool xor is true.', + self::logicalXor( + self::isBool(), + self::isTrue(), + ), + true, + ], + + [ + false, + 'is of type bool and is true xor is of type bool and is true', + 'Failed asserting that true is of type bool and is true xor is of type bool and is true.', + self::logicalXor( + self::logicalAnd( + self::isBool(), + self::isTrue(), + ), + self::logicalAnd( + self::isBool(), + self::isTrue(), + ), + ), + true, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $constraintAsString, string $failureDescription, LogicalXor $constraint, mixed $actual): void + { + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + #[DataProvider('provider')] + public function testCanBeRepresentedAsString(bool $result, string $constraintAsString, string $failureDescription, LogicalXor $constraint, mixed $actual): void + { + $this->assertSame($constraintAsString, $constraint->toString()); + } + + public function testIsCountable(): void + { + $constraint = $this->logicalXor( + $this->isBool(), + true, + ); + + $this->assertCount(2, $constraint); + } +} diff --git a/tests/unit/Framework/Constraint/String/IsJsonTest.php b/tests/unit/Framework/Constraint/String/IsJsonTest.php new file mode 100644 index 00000000000..a21e0b2b569 --- /dev/null +++ b/tests/unit/Framework/Constraint/String/IsJsonTest.php @@ -0,0 +1,79 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function json_encode; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsJson::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsJsonTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + json_encode(['key' => 'value']), + ], + + [ + false, + 'Failed asserting that an empty string is valid JSON.', + '', + ], + + [ + false, + 'Failed asserting that a string is valid JSON (Syntax error, malformed JSON).', + 'invalid json', + ], + + [ + false, + 'Failed asserting that an array is valid JSON.', + [], + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $actual): void + { + $constraint = new IsJson; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is valid JSON', (new IsJson)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsJson)); + } +} diff --git a/tests/unit/Framework/Constraint/String/RegularExpressionTest.php b/tests/unit/Framework/Constraint/String/RegularExpressionTest.php new file mode 100644 index 00000000000..9d78096e07b --- /dev/null +++ b/tests/unit/Framework/Constraint/String/RegularExpressionTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(RegularExpression::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class RegularExpressionTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + '/.*/', + 'string', + ], + + [ + false, + 'Failed asserting that \'string\' matches PCRE pattern "/[0-9]/".', + '/[0-9]/', + 'string', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, string $actual): void + { + $constraint = new RegularExpression($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('matches PCRE pattern "/.*/"', new RegularExpression('/.*/')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new RegularExpression('/.*/'))); + } +} diff --git a/tests/unit/Framework/Constraint/String/StringContainsTest.php b/tests/unit/Framework/Constraint/String/StringContainsTest.php new file mode 100644 index 00000000000..20c96b81d5f --- /dev/null +++ b/tests/unit/Framework/Constraint/String/StringContainsTest.php @@ -0,0 +1,235 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(StringContains::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class StringContainsTest extends TestCase +{ + public static function providesEvaluationCases(): array + { + return [ + 'It finds the needle with default options given' => [ + true, + '', + false, + false, + 'needle', + 'prefix needle suffix', + ], + + 'Empty needles are supported with default options given' => [ + true, + '', + false, + false, + '', + 'prefix needle suffix', + ], + + 'It finds the needle with default options given but different encodings are used' => [ + true, + '', + false, + false, + 'character', // Example ASCII needle string + 'Example character encoding string', // Example UTF-8 haystack string + ], + + 'It finds the needle given letter casing is ignored and both haystack and needle are in the same case' => [ + true, + '', + true, + false, + 'needle', + 'prefix needle suffix', + ], + + 'It finds the needle given letter casing is ignored and needle is in a different case to haystack' => [ + true, + '', + true, + false, + 'needle', + 'prefix NEEDLE suffix', + ], + + 'It finds the needle given letter casing is ignored and haystack is in a different case to needle' => [ + true, + '', + true, + false, + 'NEEDLE', + 'prefix needle suffix', + ], + + 'Needles containing only line endings are supported given line endings are set up to be ignored' => [ + true, + '', + false, + true, + "\n", + "prefix needle\r\n suffix", + ], + + 'It supports the needle and haystack using different line endings given line endings are ignored' => [ + true, + '', + false, + true, + "needle\r suffix", + "prefix needle\n suffix", + ], + + '\r\n line endings will be ignored in the needle given line endings are set up to be ignored' => [ + true, + '', + false, + true, + "needle\r\n suffix", + "prefix needle\r suffix", + ], + + '\r\n line endings will be ignored in the haystack given line endings are set up to be ignored' => [ + true, + '', + true, + true, + "needle\n", + "prefix NEEDLE\r\n suffix", + ], + + 'It fails to find the needle given the haystack is null' => [ + false, + 'Failed asserting that null [Encoding detection failed](length: 0) contains "needle" [ASCII](length: 6).', + false, + false, + 'needle', + null, + ], + + 'It fails to find the needle given the haystack does not contain it' => [ + false, + 'Failed asserting that \'prefix ... suffix\' [ASCII](length: 17) contains "needle" [ASCII](length: 6).', + false, + false, + 'needle', + 'prefix ... suffix', + ], + + 'Encoding is ignored given letter casing is ignored' => [ + false, + 'Failed asserting that \'Example UTF-8 encoded string £$\' [Encoding ignored](length: 32) contains "example ascii encoded string that is not a needle of the utf-8 one" [Encoding ignored](length: 66).', + true, + false, + 'Example ASCII encoded string that is not a needle of the UTF-8 one', + 'Example UTF-8 encoded string £$', + ], + + 'The length and detecting encoding is included in the failure message' => [ + false, + 'Failed asserting that \'Example character encoding\' [UTF-8](length: 30) contains "Example character encoding" [ASCII](length: 26).', + false, + false, + /** + * Below is an ASCII string using a 'blank space' character (code 32 in https://smartwebworker.com/ascii-codes) + * between each word. + */ + 'Example character encoding', + /** + * Below is a UTF-8 string using a 'thin-space' character (https://www.compart.com/en/unicode/U+2009) + * between each word instead of usual 'space' character (https://www.compart.com/en/unicode/U+0020). + */ + 'Example character encoding', + ], + + 'Both the needle and haystack length in the failure message partly account for \r line endings given line endings are ignored' => [ + false, + "Failed asserting that 'Some haystack with\\r\n line\\n\n endings \\n\\r\n' [ASCII](length: 36) contains \"Some needle with\n line\n endings \n\n\" [ASCII](length: 34).", + false, + true, + /** + * See StringContains::normalizeLineEndings() to + * see how "\r" are mapped to "\n". + */ + "Some needle with\r line\n endings \n\r", // 38 characters long + "Some haystack with\r line\n endings \n\r", // 39 characters long + ], + ]; + } + + public static function providesToStringRepresentationCases(): array + { + return [ + 'It contains the needle\'s string, length, and encoding information' => [ + 'contains "needle" [ASCII](length: 6)', + 'needle', + false, + false, + ], + + 'It contains the needle\'s string, length, and encoding information when using a non-ASCII encoding' => [ + 'contains "example UTF-8 needle £$" [UTF-8](length: 24)', + 'example UTF-8 needle £$', + false, + false, + ], + + 'It contains the converted-to-lower-case needle string given letter casing is ignored' => [ + 'contains "needle" [Encoding ignored](length: 6)', + 'NEEDLE', + true, + false, + ], + + 'It maps out the \r line endings from needle string given line endings are ignored' => [ + 'contains "NEEDLE' . "\n" . '" [ASCII](length: 7)', + "NEEDLE\r\n", + false, + true, + ], + ]; + } + + #[DataProvider('providesEvaluationCases')] + public function testCanBeEvaluated(bool $result, string $failureDescription, bool $ignoreCase, bool $ignoreLineEndings, string $needle, mixed $haystack): void + { + $constraint = new StringContains($needle, $ignoreCase, $ignoreLineEndings); + + $this->assertSame($result, $constraint->evaluate($haystack, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($haystack); + } + + #[DataProvider('providesToStringRepresentationCases')] + public function testCanBeRepresentedAsString(string $expected, string $needle, bool $ignoreCase, bool $ignoreLineEndings): void + { + $this->assertSame($expected, new StringContains($needle, $ignoreCase, $ignoreLineEndings)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new StringContains('needle'))); + } +} diff --git a/tests/unit/Framework/Constraint/String/StringEndsWithTest.php b/tests/unit/Framework/Constraint/String/StringEndsWithTest.php new file mode 100644 index 00000000000..42e8d74b0b1 --- /dev/null +++ b/tests/unit/Framework/Constraint/String/StringEndsWithTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\EmptyStringException; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(StringEndsWith::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class StringEndsWithTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 'suffix', + 'prefix substring suffix', + ], + + [ + false, + 'Failed asserting that \'prefix substring\' ends with "suffix".', + 'suffix', + 'prefix substring', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, string $actual): void + { + $constraint = new StringEndsWith($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('ends with "suffix"', new StringEndsWith('suffix')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new StringEndsWith('suffix'))); + } + + public function testRejectsEmptySuffix(): void + { + $this->expectException(EmptyStringException::class); + + new StringEndsWith(''); + } +} diff --git a/tests/unit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndingsTest.php b/tests/unit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndingsTest.php new file mode 100644 index 00000000000..e0fbc979bf4 --- /dev/null +++ b/tests/unit/Framework/Constraint/String/StringEqualsStringIgnoringLineEndingsTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(StringEqualsStringIgnoringLineEndings::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class StringEqualsStringIgnoringLineEndingsTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + "string\r", + "string\r\n", + ], + + [ + false, + 'Failed asserting that \'another string\' is equal to "string" ignoring line endings.', + 'string', + 'another string', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, string $actual): void + { + $constraint = new StringEqualsStringIgnoringLineEndings($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is equal to "string" ignoring line endings', new StringEqualsStringIgnoringLineEndings('string')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new StringEqualsStringIgnoringLineEndings('string'))); + } +} diff --git a/tests/unit/Framework/Constraint/String/StringMatchesFormatDescriptionTest.php b/tests/unit/Framework/Constraint/String/StringMatchesFormatDescriptionTest.php new file mode 100644 index 00000000000..9447f286462 --- /dev/null +++ b/tests/unit/Framework/Constraint/String/StringMatchesFormatDescriptionTest.php @@ -0,0 +1,347 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(StringMatchesFormatDescription::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class StringMatchesFormatDescriptionTest extends TestCase +{ + public function testConstraintStringMatchesDirectorySeparator(): void + { + $constraint = new StringMatchesFormatDescription('*%e*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('*a*', '', true)); + + $this->assertTrue($constraint->evaluate('*' . DIRECTORY_SEPARATOR . '*', '', true)); + } + + public function testConstraintStringMatchesString(): void + { + $constraint = new StringMatchesFormatDescription('*%s*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate("*\n*", '', true)); + + $this->assertTrue($constraint->evaluate('***', '', true)); + $this->assertTrue($constraint->evaluate('*foo 123 bar*', '', true)); + } + + public function testConstraintStringMatchesOptionalString(): void + { + $constraint = new StringMatchesFormatDescription('*%S*'); + + $this->assertFalse($constraint->evaluate('*', '', true)); + $this->assertFalse($constraint->evaluate("*\n*", '', true)); + + $this->assertTrue($constraint->evaluate('***', '', true)); + $this->assertTrue($constraint->evaluate('*foo 123 bar*', '', true)); + $this->assertTrue($constraint->evaluate('**', '', true)); + } + + public function testConstraintStringMatchesAnything(): void + { + $constraint = new StringMatchesFormatDescription('*%a*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + + $this->assertTrue($constraint->evaluate('***', '', true)); + $this->assertTrue($constraint->evaluate('*foo 123 bar*', '', true)); + $this->assertTrue($constraint->evaluate("*\n*", '', true)); + } + + public function testConstraintStringMatchesOptionalAnything(): void + { + $constraint = new StringMatchesFormatDescription('*%A*'); + + $this->assertFalse($constraint->evaluate('*', '', true)); + + $this->assertTrue($constraint->evaluate('***', '', true)); + $this->assertTrue($constraint->evaluate('*foo 123 bar*', '', true)); + $this->assertTrue($constraint->evaluate("*\n*", '', true)); + $this->assertTrue($constraint->evaluate('**', '', true)); + } + + public function testConstraintStringMatchesWhitespace(): void + { + $constraint = new StringMatchesFormatDescription('*%w*'); + + $this->assertFalse($constraint->evaluate('*', '', true)); + $this->assertFalse($constraint->evaluate('*a*', '', true)); + + $this->assertTrue($constraint->evaluate('* *', '', true)); + $this->assertTrue($constraint->evaluate("*\t\n*", '', true)); + $this->assertTrue($constraint->evaluate('**', '', true)); + } + + public function testConstraintStringMatchesInteger(): void + { + $constraint = new StringMatchesFormatDescription('*%i*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('*a*', '', true)); + $this->assertFalse($constraint->evaluate('*1.0*', '', true)); + + $this->assertTrue($constraint->evaluate('*0*', '', true)); + $this->assertTrue($constraint->evaluate('*12*', '', true)); + $this->assertTrue($constraint->evaluate('*-1*', '', true)); + $this->assertTrue($constraint->evaluate('*+2*', '', true)); + } + + public function testConstraintStringMatchesUnsignedInt(): void + { + $constraint = new StringMatchesFormatDescription('*%d*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('*a*', '', true)); + $this->assertFalse($constraint->evaluate('*1.0*', '', true)); + $this->assertFalse($constraint->evaluate('*-1*', '', true)); + $this->assertFalse($constraint->evaluate('*+2*', '', true)); + + $this->assertTrue($constraint->evaluate('*0*', '', true)); + $this->assertTrue($constraint->evaluate('*12*', '', true)); + } + + public function testConstraintStringMatchesHexadecimal(): void + { + $constraint = new StringMatchesFormatDescription('*%x*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('***', '', true)); + $this->assertFalse($constraint->evaluate('*g*', '', true)); + $this->assertFalse($constraint->evaluate('*1.0*', '', true)); + $this->assertFalse($constraint->evaluate('*-1*', '', true)); + $this->assertFalse($constraint->evaluate('*+2*', '', true)); + + $this->assertTrue($constraint->evaluate('*0f0f0f*', '', true)); + $this->assertTrue($constraint->evaluate('*0*', '', true)); + $this->assertTrue($constraint->evaluate('*12*', '', true)); + $this->assertTrue($constraint->evaluate('*a*', '', true)); + } + + public function testConstraintStringMatchesFloat(): void + { + $constraint = new StringMatchesFormatDescription('*%f*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('***', '', true)); + $this->assertFalse($constraint->evaluate('*a*', '', true)); + $this->assertFalse($constraint->evaluate('*1.*', '', true)); + + $this->assertTrue($constraint->evaluate('*1.0*', '', true)); + $this->assertTrue($constraint->evaluate('*0*', '', true)); + $this->assertTrue($constraint->evaluate('*12*', '', true)); + $this->assertTrue($constraint->evaluate('*.1*', '', true)); + $this->assertTrue($constraint->evaluate('*2e3*', '', true)); + $this->assertTrue($constraint->evaluate('*-2.34e-56*', '', true)); + $this->assertTrue($constraint->evaluate('*+2.34e+56*', '', true)); + } + + public function testConstraintStringMatchesCharacter(): void + { + $constraint = new StringMatchesFormatDescription('*%c*'); + + $this->assertFalse($constraint->evaluate('**', '', true)); + $this->assertFalse($constraint->evaluate('*ab*', '', true)); + + $this->assertTrue($constraint->evaluate('***', '', true)); + $this->assertTrue($constraint->evaluate('*a*', '', true)); + $this->assertTrue($constraint->evaluate('*g*', '', true)); + $this->assertTrue($constraint->evaluate('*0*', '', true)); + $this->assertTrue($constraint->evaluate('*2*', '', true)); + $this->assertTrue($constraint->evaluate('* *', '', true)); + $this->assertTrue($constraint->evaluate("*\n*", '', true)); + } + + public function testConstraintStringMatchesEscapedPercent(): void + { + $constraint = new StringMatchesFormatDescription('%%,%%e,%%s,%%S,%%a,%%A,%%w,%%i,%%d,%%x,%%f,%%c,%%Z,%%%%,%%'); + + $this->assertFalse($constraint->evaluate('%%,%' . DIRECTORY_SEPARATOR . ',%*,%*,%*,%*,% ,%0,%0,%0f0f0f,%1.0,%*,%%Z,%%%%,%%', '', true)); + $this->assertTrue($constraint->evaluate('%,%e,%s,%S,%a,%A,%w,%i,%d,%x,%f,%c,%Z,%%,%', '', true)); + } + + public function testConstraintStringMatchesEscapedPercentThenPlaceholder(): void + { + $constraint = new StringMatchesFormatDescription('%%%e,%%%s,%%%S,%%%a,%%%A,%%%w,%%%i,%%%d,%%%x,%%%f,%%%c'); + + $this->assertFalse($constraint->evaluate('%%e,%%s,%%S,%%a,%%A,%%w,%%i,%%d,%%x,%%f,%%c', '', true)); + $this->assertTrue($constraint->evaluate('%' . DIRECTORY_SEPARATOR . ',%*,%*,%*,%*,% ,%0,%0,%0f0f0f,%1.0,%*', '', true)); + } + + public function testConstraintStringMatchesSlash(): void + { + $constraint = new StringMatchesFormatDescription('/'); + + $this->assertFalse($constraint->evaluate('\\/', '', true)); + $this->assertTrue($constraint->evaluate('/', '', true)); + } + + public function testConstraintStringMatchesBackslash(): void + { + $constraint = new StringMatchesFormatDescription('\\'); + + $this->assertFalse($constraint->evaluate('\\\\', '', true)); + $this->assertTrue($constraint->evaluate('\\', '', true)); + } + + public function testConstraintStringMatchesBackslashSlash(): void + { + $constraint = new StringMatchesFormatDescription('\\/'); + + $this->assertFalse($constraint->evaluate('/', '', true)); + $this->assertTrue($constraint->evaluate('\\/', '', true)); + } + + public function testConstraintStringMatchesNewline(): void + { + $constraint = new StringMatchesFormatDescription("\r\n"); + + $this->assertFalse($constraint->evaluate("*\r\n", '', true)); + $this->assertTrue($constraint->evaluate("\r\n", '', true)); + } + + public function testConstraintStringMatchesAnythingMultiline(): void + { + $constraint = new StringMatchesFormatDescription("*\n%a\nbar\nbaz"); + + $this->assertFalse($constraint->evaluate("*\n*", '', true)); + } + + public function testFailureMessageWithNewlines(): void + { + $constraint = new StringMatchesFormatDescription("%c\nfoo\n%c"); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage( + <<<'EOD' +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ + * +-foo ++bar + * + +EOD + ); + + $constraint->evaluate("*\nbar\n*"); + } + + public function testFailureMessageWithNewlinesAndAnythingMatcher(): void + { + $constraint = new StringMatchesFormatDescription("%a\nfoo\n%s\nbar"); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage( + <<<'EOD' +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ + * + foo + * +-bar ++mismatch + +EOD + ); + + $constraint->evaluate("*\nfoo\n*\nmismatch"); + } + + public function testFailureMessageWithNewlinesAndAnythingMatcherMultilineMatches(): void + { + $constraint = new StringMatchesFormatDescription( + <<<'EOD' +## before first A +%A +## after first A +* +## before second A +%A +## after second A +* +Foo: %s + +EOD + ); + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage( + <<<'EOD' +Failed asserting that string matches format description. +--- Expected ++++ Actual +@@ @@ + ## before first A + some multiline ++text for ++A to match + ## after first A + * + ## before second A ++more multiline text ++for A to match ++## after second A + * +-## after second A ++Foo: s match + * +-Foo: %s ++Additional Text that is not matched + +EOD + ); + + $constraint->evaluate( + <<<'EOD' +## before first A +some multiline +text for +A to match +## after first A +* +## before second A +more multiline text +for A to match +## after second A +* +Foo: s match +* +Additional Text that is not matched +EOD + ); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame( + 'matches format description:' . PHP_EOL . 'string', + new StringMatchesFormatDescription('string')->toString(), + ); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new StringMatchesFormatDescription('string'))); + } +} diff --git a/tests/unit/Framework/Constraint/String/StringStartsWithTest.php b/tests/unit/Framework/Constraint/String/StringStartsWithTest.php new file mode 100644 index 00000000000..c60d3104b49 --- /dev/null +++ b/tests/unit/Framework/Constraint/String/StringStartsWithTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\EmptyStringException; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(StringStartsWith::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class StringStartsWithTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 'prefix', + 'prefix substring suffix', + ], + + [ + false, + 'Failed asserting that \'substring suffix\' starts with "prefix".', + 'prefix', + 'substring suffix', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, string $actual): void + { + $constraint = new StringStartsWith($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('starts with "prefix"', new StringStartsWith('prefix')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new StringStartsWith('prefix'))); + } + + public function testRejectsEmptyPrefix(): void + { + $this->expectException(EmptyStringException::class); + + new StringStartsWith(''); + } +} diff --git a/tests/unit/Framework/Constraint/Traversable/ArrayHasKeyTest.php b/tests/unit/Framework/Constraint/Traversable/ArrayHasKeyTest.php new file mode 100644 index 00000000000..5dbccaa9bb3 --- /dev/null +++ b/tests/unit/Framework/Constraint/Traversable/ArrayHasKeyTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use ArrayObject; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ArrayHasKey::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class ArrayHasKeyTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + 0, + [0 => 'value'], + ], + + [ + true, + '', + 'key', + ['key' => 'value'], + ], + + [ + true, + '', + 'key', + new ArrayObject(['key' => 'value']), + ], + + [ + false, + 'Failed asserting that an array has the key 1.', + 1, + [0 => 'value'], + ], + + [ + false, + 'Failed asserting that an array has the key \'another-key\'.', + 'another-key', + ['key' => 'value'], + ], + + [ + false, + 'Failed asserting that an array has the key \'another-key\'.', + 'another-key', + new ArrayObject(['key' => 'value']), + ], + + [ + false, + 'Failed asserting that an array has the key \'key\'.', + 'key', + null, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, int|string $expected, mixed $actual): void + { + $constraint = new ArrayHasKey($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('has the key 0', new ArrayHasKey(0)->toString()); + $this->assertSame('has the key \'key\'', new ArrayHasKey('key')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new ArrayHasKey(0))); + } +} diff --git a/tests/unit/Framework/Constraint/Traversable/IsListTest.php b/tests/unit/Framework/Constraint/Traversable/IsListTest.php new file mode 100644 index 00000000000..1e734aee999 --- /dev/null +++ b/tests/unit/Framework/Constraint/Traversable/IsListTest.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsList::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsListTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + [0 => 'value', 1 => 'another-value'], + ], + + [ + false, + 'Failed asserting that an array is a list.', + ['key' => 'value'], + ], + + [ + false, + 'Failed asserting that an integer is a list.', + 0, + ], + + [ + false, + 'Failed asserting that an instance of class stdClass is a list.', + new stdClass, + ], + + [ + false, + 'Failed asserting that a boolean is a list.', + false, + ], + + [ + false, + 'Failed asserting that a float is a list.', + 0.0, + ], + + [ + false, + 'Failed asserting that a resource is a list.', + fopen(__FILE__, 'r'), + ], + + [ + false, + 'Failed asserting that a closed resource is a list.', + self::closedResource(), + ], + + [ + false, + 'Failed asserting that null is a list.', + null, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $actual): void + { + $constraint = new IsList; + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is a list', (new IsList)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new IsList)); + } + + private static function closedResource() + { + $resource = fopen(__FILE__, 'r'); + + fclose($resource); + + return $resource; + } +} diff --git a/tests/unit/Framework/Constraint/Traversable/TraversableContainsEqualTest.php b/tests/unit/Framework/Constraint/Traversable/TraversableContainsEqualTest.php new file mode 100644 index 00000000000..c261db93e80 --- /dev/null +++ b/tests/unit/Framework/Constraint/Traversable/TraversableContainsEqualTest.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use SplObjectStorage; +use stdClass; + +#[CoversClass(TraversableContainsEqual::class)] +#[CoversClass(TraversableContains::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class TraversableContainsEqualTest extends TestCase +{ + public static function provider(): array + { + $o = new stdClass; + + $s = new SplObjectStorage; + $s->offsetSet($o); + + return [ + [ + true, + '', + 0, + [0], + ], + + [ + true, + '', + 'value', + ['value'], + ], + + [ + true, + '', + $o, + [$o], + ], + + [ + true, + '', + $o, + $s, + ], + + [ + true, + '', + '0', + [0], + ], + + [ + true, + '', + 0, + ['0'], + ], + + [ + false, + 'Failed asserting that an array contains stdClass Object', + $o, + [], + ], + + [ + false, + 'Failed asserting that a traversable contains stdClass Object', + $o, + new SplObjectStorage, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $expected, mixed $actual): void + { + $constraint = new TraversableContainsEqual($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('contains \'value\'', new TraversableContainsEqual('value')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new TraversableContainsEqual('value'))); + } +} diff --git a/tests/unit/Framework/Constraint/Traversable/TraversableContainsIdenticalTest.php b/tests/unit/Framework/Constraint/Traversable/TraversableContainsIdenticalTest.php new file mode 100644 index 00000000000..59938248045 --- /dev/null +++ b/tests/unit/Framework/Constraint/Traversable/TraversableContainsIdenticalTest.php @@ -0,0 +1,118 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use SplObjectStorage; +use stdClass; + +#[CoversClass(TraversableContainsIdentical::class)] +#[CoversClass(TraversableContains::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class TraversableContainsIdenticalTest extends TestCase +{ + public static function provider(): array + { + $o = new stdClass; + + $s = new SplObjectStorage; + $s->offsetSet($o); + + return [ + [ + true, + '', + 0, + [0], + ], + + [ + true, + '', + 'value', + ['value'], + ], + + [ + true, + '', + $o, + [$o], + ], + + [ + true, + '', + $o, + $s, + ], + + [ + false, + 'Failed asserting that an array contains stdClass Object', + $o, + [], + ], + + [ + false, + 'Failed asserting that a traversable contains stdClass Object', + $o, + new SplObjectStorage, + ], + + [ + false, + 'Failed asserting that an array contains \'0\'.', + '0', + [0], + ], + + [ + false, + 'Failed asserting that an array contains 0.', + 0, + ['0'], + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, mixed $expected, mixed $actual): void + { + $constraint = new TraversableContainsIdentical($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('contains \'value\'', new TraversableContainsIdentical('value')->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, (new TraversableContainsIdentical('value'))); + } +} diff --git a/tests/unit/Framework/Constraint/Traversable/TraversableContainsOnlyTest.php b/tests/unit/Framework/Constraint/Traversable/TraversableContainsOnlyTest.php new file mode 100644 index 00000000000..0d272f2f4ce --- /dev/null +++ b/tests/unit/Framework/Constraint/Traversable/TraversableContainsOnlyTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\NativeType; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(TraversableContainsOnly::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class TraversableContainsOnlyTest extends TestCase +{ + public static function nativeTypeProvider(): array + { + return [ + [ + true, + '', + NativeType::Int, + [0, 1, 2], + ], + + [ + false, + <<<'EOT' +Failed asserting that Array &0 [ + 0 => 0, + 1 => '1', + 2 => 2, +] contains only values of type "int". +EOT, + NativeType::Int, + [0, '1', 2], + ], + ]; + } + + public static function classOrInterfaceProvider(): array + { + return [ + [ + true, + '', + stdClass::class, + [new stdClass, new stdClass], + ], + + [ + false, + <<<'EOT' +Failed asserting that Array &0 [ + 0 => null, +] contains only values of type "stdClass". +EOT, + stdClass::class, + [null], + ], + ]; + } + + #[DataProvider('nativeTypeProvider')] + public function testCanBeEvaluatedForNativeType(bool $result, string $failureDescription, NativeType $expected, mixed $actual): void + { + $constraint = TraversableContainsOnly::forNativeType($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + /** + * @param class-string $expected + */ + #[DataProvider('classOrInterfaceProvider')] + public function testCanBeEvaluatedForClassOrInterface(bool $result, string $failureDescription, string $expected, mixed $actual): void + { + $constraint = TraversableContainsOnly::forClassOrInterface($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsStringForNativeType(): void + { + $this->assertSame('contains only values of type "int"', TraversableContainsOnly::forNativeType(NativeType::Int)->toString()); + } + + public function testCanBeRepresentedAsStringForClassOrInterface(): void + { + $this->assertSame('contains only values of type "stdClass"', TraversableContainsOnly::forClassOrInterface(stdClass::class)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, TraversableContainsOnly::forNativeType(NativeType::Int)); + } +} diff --git a/tests/unit/Framework/Constraint/Type/IsInstanceOfTest.php b/tests/unit/Framework/Constraint/Type/IsInstanceOfTest.php new file mode 100644 index 00000000000..924fabc559e --- /dev/null +++ b/tests/unit/Framework/Constraint/Type/IsInstanceOfTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\UnknownClassOrInterfaceException; +use stdClass; +use Throwable; + +#[CoversClass(IsInstanceOf::class)] +#[CoversClass(Constraint::class)] +#[CoversClass(UnknownClassOrInterfaceException::class)] +#[Small] +final class IsInstanceOfTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + stdClass::class, + new stdClass, + ], + + [ + false, + 'Failed asserting that an instance of anonymous class created at', + stdClass::class, + new class + {}, + ], + + [ + false, + 'Failed asserting that an instance of class Exception is an instance of class stdClass.', + stdClass::class, + new Exception, + ], + + [ + false, + 'Failed asserting that an instance of class stdClass is an instance of interface Throwable.', + Throwable::class, + new stdClass, + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, string $expected, mixed $actual): void + { + $constraint = new IsInstanceOf($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is an instance of class stdClass', new IsInstanceOf(stdClass::class)->toString()); + $this->assertSame('is an instance of interface Throwable', new IsInstanceOf(Throwable::class)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, new IsInstanceOf(stdClass::class)); + } + + public function testRejectsUnknownTypes(): void + { + $this->expectException(UnknownClassOrInterfaceException::class); + + new IsInstanceOf('Does\Not\Exist'); + } +} diff --git a/tests/unit/Framework/Constraint/Type/IsNullTest.php b/tests/unit/Framework/Constraint/Type/IsNullTest.php new file mode 100644 index 00000000000..f5008a9b2c3 --- /dev/null +++ b/tests/unit/Framework/Constraint/Type/IsNullTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IsNull::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsNullTest extends TestCase +{ + public function testCanBeEvaluated(): void + { + $constraint = new IsNull; + + $this->assertTrue($constraint->evaluate(null, returnResult: true)); + $this->assertFalse($constraint->evaluate(false, returnResult: true)); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is null', (new IsNull)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, new IsNull); + } +} diff --git a/tests/unit/Framework/Constraint/Type/IsTypeTest.php b/tests/unit/Framework/Constraint/Type/IsTypeTest.php new file mode 100644 index 00000000000..e71f8c7bcd2 --- /dev/null +++ b/tests/unit/Framework/Constraint/Type/IsTypeTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\Constraint; + +use function fclose; +use function fopen; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\NativeType; +use PHPUnit\Framework\TestCase; +use stdClass; + +#[CoversClass(IsType::class)] +#[CoversClass(Constraint::class)] +#[Small] +final class IsTypeTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + true, + '', + NativeType::Numeric, + 0, + ], + + [ + true, + '', + NativeType::Int, + 0, + ], + + [ + true, + '', + NativeType::Float, + 0.0, + ], + + [ + true, + '', + NativeType::String, + 'string', + ], + + [ + true, + '', + NativeType::Bool, + false, + ], + + [ + true, + '', + NativeType::Null, + null, + ], + + [ + true, + '', + NativeType::Array, + [], + ], + + [ + true, + '', + NativeType::Object, + new stdClass, + ], + + [ + true, + '', + NativeType::Resource, + fopen(__FILE__, 'r'), + ], + + [ + true, + '', + NativeType::ClosedResource, + self::closedResource(), + ], + + [ + true, + '', + NativeType::Scalar, + 0, + ], + + [ + true, + '', + NativeType::Callable, + static fn () => true, + ], + + [ + true, + '', + NativeType::Iterable, + [], + ], + ]; + } + + #[DataProvider('provider')] + public function testCanBeEvaluated(bool $result, string $failureDescription, NativeType $expected, mixed $actual): void + { + $constraint = new IsType($expected); + + $this->assertSame($result, $constraint->evaluate($actual, returnResult: true)); + + if ($result) { + return; + } + + $this->expectException(ExpectationFailedException::class); + $this->expectExceptionMessage($failureDescription); + + $constraint->evaluate($actual); + } + + public function testCanBeRepresentedAsString(): void + { + $this->assertSame('is of type array', new IsType(NativeType::Array)->toString()); + } + + public function testIsCountable(): void + { + $this->assertCount(1, new IsType(NativeType::Array)); + } + + private static function closedResource() + { + $resource = fopen(__FILE__, 'r'); + + fclose($resource); + + return $resource; + } +} diff --git a/tests/unit/Framework/Exception/ExceptionTest.php b/tests/unit/Framework/Exception/ExceptionTest.php new file mode 100644 index 00000000000..c19badaede8 --- /dev/null +++ b/tests/unit/Framework/Exception/ExceptionTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(Exception::class)] +#[Small] +final class ExceptionTest extends TestCase +{ + public function testExceptionSerialize(): void + { + $actual = (new Exception)->__serialize(); + + $this->assertCount(5, $actual); + $this->assertArrayHasKey('serializableTrace', $actual); + $this->assertArrayHasKey('message', $actual); + $this->assertArrayHasKey('code', $actual); + $this->assertArrayHasKey('file', $actual); + $this->assertArrayHasKey('line', $actual); + } +} diff --git a/tests/unit/Framework/ExecutionOrderDependencyTest.php b/tests/unit/Framework/ExecutionOrderDependencyTest.php new file mode 100644 index 00000000000..95932d172ba --- /dev/null +++ b/tests/unit/Framework/ExecutionOrderDependencyTest.php @@ -0,0 +1,124 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; + +#[CoversClass(ExecutionOrderDependency::class)] +class ExecutionOrderDependencyTest extends TestCase +{ + public static function createFromParametersProvider(): array + { + return [ + // Dependency on specific class::method target + ['Class1', 'test1', 'Class1::test1', false], + ['Class2', 'test2', 'Class2::test2', false], + ['Class3::method3', null, 'Class3::method3', false], + + // Dependency on whole class + ['Class4', null, 'Class4::class', true], + ['Class5', '', 'Class5::class', true], + ['Class6', 'class', 'Class6::class', true], + ['Class7::class', null, 'Class7::class', true], + ]; + } + + public static function createWithCloneOptionProvider(): array + { + return [ + 'no clone' => [false, false, false, false], + 'deep clone' => [true, false, false, true], + 'shallow clone' => [false, true, true, false], + ]; + } + + public function testCreateDependencyOnClassFromClassNameOnly(): void + { + $dependency = new ExecutionOrderDependency('ClassDependency'); + + $this->assertTrue($dependency->targetIsClass()); + $this->assertSame('ClassDependency::class', $dependency->getTarget()); + $this->assertSame('ClassDependency', $dependency->getTargetClassName()); + } + + #[DataProvider('createFromParametersProvider')] + public function testCreateDependencyFromParameters( + string $className, + ?string $methodName, + string $expectedTarget, + bool $expectedTargetIsClass + ): void { + $dependency = new ExecutionOrderDependency($className, $methodName); + + $this->assertSame( + $expectedTarget, + $dependency->getTarget(), + 'Incorrect dependency class::method target', + ); + + $this->assertSame( + $expectedTargetIsClass, + $dependency->targetIsClass(), + 'Incorrect targetIsClass', + ); + } + + #[DataProvider('createWithCloneOptionProvider')] + public function testCreateDependencyWithCloneOption(bool $deepClone, bool $shallowClone, bool $expectedShallowClone, bool $expectedDeepClone): void + { + $dependency = new ExecutionOrderDependency('ClassName', 'methodName', $deepClone, $shallowClone); + + $this->assertSame( + $expectedShallowClone, + $dependency->shallowClone(), + 'Incorrect shallowClone option', + ); + + $this->assertSame( + $expectedDeepClone, + $dependency->deepClone(), + 'Incorrect clone option', + ); + } + + public function testMergeHandlesEmptyDependencyLists(): void + { + $depOne = new ExecutionOrderDependency('classOne'); + $depTwo = new ExecutionOrderDependency('classTwo::methodTwo'); + + $this->assertSame( + [$depOne, $depTwo], + ExecutionOrderDependency::mergeUnique( + [], + [$depOne, $depTwo], + ), + 'Left side of merge could be empty', + ); + + $this->assertSame( + [$depOne, $depTwo], + ExecutionOrderDependency::mergeUnique( + [$depOne, $depTwo], + [], + ), + 'Right side of merge could be empty', + ); + } + + public function testEmptyClassOrCallable(): void + { + $empty = new ExecutionOrderDependency(''); + $this->assertFalse($empty->shallowClone()); + $this->assertFalse($empty->deepClone()); + $this->assertFalse($empty->targetIsClass()); + $this->assertSame('', $empty->getTargetClassName()); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateConfiguredMockTest.php b/tests/unit/Framework/MockObject/Creation/CreateConfiguredMockTest.php new file mode 100644 index 00000000000..51ba60a16ce --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateConfiguredMockTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createConfiguredMock()')] +final class CreateConfiguredMockTest extends TestCase +{ + public function testCreatesMockObjectForInterfaceOrExtendableClassWithReturnValueConfigurationForMultipleMethods(): void + { + $double = $this->createConfiguredMock( + InterfaceWithReturnTypeDeclaration::class, + [ + 'doSomething' => true, + 'doSomethingElse' => 1, + ], + ); + + $this->assertTrue($double->doSomething()); + $this->assertSame(1, $double->doSomethingElse(0)); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateConfiguredStubTest.php b/tests/unit/Framework/MockObject/Creation/CreateConfiguredStubTest.php new file mode 100644 index 00000000000..445947fd291 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateConfiguredStubTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('createConfiguredStub()')] +final class CreateConfiguredStubTest extends TestCase +{ + public function testCreatesTestStubForInterfaceOrExtendableClassWithReturnValueConfigurationForMultipleMethods(): void + { + $double = $this->createConfiguredStub( + InterfaceWithReturnTypeDeclaration::class, + [ + 'doSomething' => true, + 'doSomethingElse' => 1, + ], + ); + + $this->assertTrue($double->doSomething()); + $this->assertSame(1, $double->doSomethingElse(0)); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesTest.php b/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesTest.php new file mode 100644 index 00000000000..b7a09cfed5d --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesTest.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\RuntimeException as GeneratorRuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownInterfaceException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterfaceThatDoesSomething; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createMockForIntersectionOfInterfaces()')] +final class CreateMockForIntersectionOfInterfacesTest extends TestCase +{ + public function testCreatesMockObjectForIntersectionOfInterfaces(): void + { + $double = $this->createMockForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->assertInstanceOf(AnInterface::class, $double); + $this->assertInstanceOf(AnotherInterface::class, $double); + $this->assertInstanceOf(Stub::class, $double); + + $double->method('doSomething')->willReturn(true); + $double->method('doSomethingElse')->willReturn(true); + + $this->assertTrue($double->doSomething()); + $this->assertTrue($double->doSomethingElse()); + } + + public function testReturnValueGenerationIsEnabledByDefault(): void + { + $double = $this->createMockForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->assertFalse($double->doSomething()); + $this->assertNull($double->doSomethingElse()); + } + + public function testCannotCreateMockObjectForIntersectionOfInterfacesWhenLessThanTwoInterfacesAreSpecified(): void + { + $this->expectException(GeneratorRuntimeException::class); + $this->expectExceptionMessage('At least two interfaces must be specified'); + + $this->createMockForIntersectionOfInterfaces([AnInterface::class]); + } + + public function testCannotCreateMockObjectForIntersectionOfUnknownInterfaces(): void + { + $this->expectException(UnknownInterfaceException::class); + + $this->createMockForIntersectionOfInterfaces(['DoesNotExist', 'DoesNotExist']); + } + + public function testCannotCreateMockObjectForIntersectionOfInterfacesThatDeclareTheSameMethod(): void + { + $this->expectException(GeneratorRuntimeException::class); + $this->expectExceptionMessage('Interfaces must not declare the same method'); + + $this->createMockForIntersectionOfInterfaces([AnInterface::class, AnotherInterfaceThatDoesSomething::class]); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php b/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php new file mode 100644 index 00000000000..a72711110b3 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateMockForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterface; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createMockForIntersectionOfInterfaces()')] +#[DisableReturnValueGenerationForTestDoubles] +final class CreateMockForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest extends TestCase +{ + public function testReturnValueGenerationCanBeDisabledWithAttribute(): void + { + $double = $this->createMockForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->expectException(ReturnValueNotConfiguredException::class); + + $double->doSomething(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateMockTest.php b/tests/unit/Framework/MockObject/Creation/CreateMockTest.php new file mode 100644 index 00000000000..4bb54486f74 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateMockTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\Enumeration; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use PHPUnit\TestFixture\MockObject\ExtendableReadonlyClass; +use PHPUnit\TestFixture\MockObject\FinalClass; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createMock()')] +final class CreateMockTest extends TestCase +{ + public function testCreatesMockObjectForInterface(): void + { + $double = $this->createMock(AnInterface::class); + + $this->assertInstanceOf(AnInterface::class, $double); + $this->assertInstanceOf(Stub::class, $double); + $this->assertInstanceOf(MockObject::class, $double); + } + + public function testCreatesMockObjectForExtendableClass(): void + { + $double = $this->createMock(ExtendableClass::class); + + $this->assertInstanceOf(ExtendableClass::class, $double); + $this->assertInstanceOf(Stub::class, $double); + $this->assertInstanceOf(MockObject::class, $double); + } + + public function testCreatesMockObjectForExtendableReadonlyClass(): void + { + $double = $this->createMock(ExtendableReadonlyClass::class); + + $this->assertInstanceOf(ExtendableReadonlyClass::class, $double); + $this->assertInstanceOf(Stub::class, $double); + $this->assertInstanceOf(MockObject::class, $double); + } + + public function testReturnValueGenerationIsEnabledByDefault(): void + { + $double = $this->createMock(AnInterface::class); + + $this->assertFalse($double->doSomething()); + } + + public function testCannotCreateMockObjectForFinalClass(): void + { + $this->expectException(ClassIsFinalException::class); + + $this->createMock(FinalClass::class); + } + + public function testCannotCreateMockObjectForEnumeration(): void + { + $this->expectException(ClassIsEnumerationException::class); + + $this->createMock(Enumeration::class); + } + + public function testCannotCreateMockObjectForUnknownType(): void + { + $this->expectException(UnknownTypeException::class); + + $this->createMock('this\does\not\exist'); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateMockWithDisabledReturnValueGenerationTest.php b/tests/unit/Framework/MockObject/Creation/CreateMockWithDisabledReturnValueGenerationTest.php new file mode 100644 index 00000000000..41b69a7d555 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateMockWithDisabledReturnValueGenerationTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createMock()')] +#[DisableReturnValueGenerationForTestDoubles] +final class CreateMockWithDisabledReturnValueGenerationTest extends TestCase +{ + public function testReturnValueGenerationCanBeDisabledWithAttribute(): void + { + $double = $this->createMock(AnInterface::class); + + $this->expectException(ReturnValueNotConfiguredException::class); + + $double->doSomething(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreatePartialMockTest.php b/tests/unit/Framework/MockObject/Creation/CreatePartialMockTest.php new file mode 100644 index 00000000000..10644401e3b --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreatePartialMockTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use ReflectionProperty; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createPartialMock()')] +final class CreatePartialMockTest extends TestCase +{ + public function testCreatesPartialMockObjectForExtendableClass(): void + { + $double = $this->createPartialMock(ExtendableClass::class, ['doSomethingElse']); + + $double->expects($this->once())->method('doSomethingElse')->willReturn(true); + + $this->assertTrue($double->doSomething()); + } + + public function testCannotCreatePartialMockObjectForExtendableClassWithDuplicateMethods(): void + { + $this->expectException(DuplicateMethodException::class); + $this->expectExceptionMessage('Cannot double using a method list that contains duplicates: "doSomethingElse, doSomethingElse" (duplicate: "doSomethingElse")'); + + $this->createPartialMock(ExtendableClass::class, ['doSomethingElse', 'doSomethingElse']); + } + + public function testMethodOfPartialMockThatIsNotConfigurableCannotBeConfigured(): void + { + $double = $this->createPartialMock(ExtendableClass::class, ['doSomethingElse']); + + try { + $double->expects($this->once())->method('doSomething')->willReturn(true); + } catch (MethodCannotBeConfiguredException $e) { + $this->assertSame('Trying to configure method "doSomething" which cannot be configured because it does not exist, has not been specified, is final, or is static', $e->getMessage()); + + return; + } finally { + $this->resetMockObjects(); + } + + $this->fail(); + } + + public function testMethodOfPartialMockThatDoesNotExistCannotBeConfigured(): void + { + $this->expectException(CannotUseOnlyMethodsException::class); + $this->expectExceptionMessage('Trying to configure method "doesNotExist" with onlyMethods(), but it does not exist in class "PHPUnit\TestFixture\MockObject\ExtendableClass"'); + + $this->createPartialMock(ExtendableClass::class, ['doesNotExist']); + } + + private function resetMockObjects(): void + { + new ReflectionProperty(TestCase::class, 'mockObjects')->setValue($this, []); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreatePartialMockWithDisabledReturnValueGenerationTest.php b/tests/unit/Framework/MockObject/Creation/CreatePartialMockWithDisabledReturnValueGenerationTest.php new file mode 100644 index 00000000000..34672c3bd1e --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreatePartialMockWithDisabledReturnValueGenerationTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\ExtendableClass; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +#[TestDox('createPartialMock()')] +#[DisableReturnValueGenerationForTestDoubles] +final class CreatePartialMockWithDisabledReturnValueGenerationTest extends TestCase +{ + public function testReturnValueGenerationCanBeDisabledWithAttribute(): void + { + $double = $this->createPartialMock(ExtendableClass::class, ['doSomething']); + + $this->expectException(ReturnValueNotConfiguredException::class); + + $double->doSomething(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesTest.php b/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesTest.php new file mode 100644 index 00000000000..758425209a7 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\RuntimeException as GeneratorRuntimeException; +use PHPUnit\Framework\MockObject\Generator\UnknownInterfaceException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterfaceThatDoesSomething; +use PHPUnit\TestFixture\MockObject\ExtendableClass; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('createStubForIntersectionOfInterfaces()')] +final class CreateStubForIntersectionOfInterfacesTest extends TestCase +{ + public function testCreatesTestStubForIntersectionOfInterfaces(): void + { + $double = $this->createStubForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->assertInstanceOf(AnInterface::class, $double); + $this->assertInstanceOf(AnotherInterface::class, $double); + $this->assertInstanceOf(Stub::class, $double); + + $double->method('doSomething')->willReturn(true); + $double->method('doSomethingElse')->willReturn(true); + + $this->assertTrue($double->doSomething()); + $this->assertTrue($double->doSomethingElse()); + } + + public function testReturnValueGenerationIsEnabledByDefault(): void + { + $double = $this->createStubForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->assertFalse($double->doSomething()); + $this->assertNull($double->doSomethingElse()); + } + + public function testCannotCreateTestStubForIntersectionOfInterfacesWhenLessThanTwoInterfacesAreSpecified(): void + { + $this->expectException(GeneratorRuntimeException::class); + $this->expectExceptionMessage('At least two interfaces must be specified'); + + $this->createStubForIntersectionOfInterfaces([AnInterface::class]); + } + + public function testCannotCreateTestStubForIntersectionOfUnknownInterfaces(): void + { + $this->expectException(UnknownInterfaceException::class); + + $this->createStubForIntersectionOfInterfaces(['DoesNotExist', 'DoesNotExist']); + } + + public function testCannotCreateTestStubForIntersectionOfInterfacesThatDeclareTheSameMethod(): void + { + $this->expectException(GeneratorRuntimeException::class); + $this->expectExceptionMessage('Interfaces must not declare the same method'); + + $this->createStubForIntersectionOfInterfaces([AnInterface::class, AnotherInterfaceThatDoesSomething::class]); + } + + public function testCannotCreateTestStubForIntersectionOfInterfacesWhenClassIsUsed(): void + { + $this->expectException(UnknownInterfaceException::class); + $this->expectExceptionMessage('Interface "PHPUnit\TestFixture\MockObject\ExtendableClass" does not exist'); + + $this->createStubForIntersectionOfInterfaces([AnInterface::class, ExtendableClass::class]); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php b/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php new file mode 100644 index 00000000000..4049f87e452 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateStubForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterface; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('createStubForIntersectionOfInterfaces()')] +#[DisableReturnValueGenerationForTestDoubles] +final class CreateStubForIntersectionOfInterfacesWithDisabledReturnValueGenerationTest extends TestCase +{ + public function testReturnValueGenerationCanBeDisabledWithAttribute(): void + { + $double = $this->createStubForIntersectionOfInterfaces([AnInterface::class, AnotherInterface::class]); + + $this->expectException(ReturnValueNotConfiguredException::class); + + $double->doSomething(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateStubTest.php b/tests/unit/Framework/MockObject/Creation/CreateStubTest.php new file mode 100644 index 00000000000..0226009ab78 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateStubTest.php @@ -0,0 +1,83 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\ClassIsEnumerationException; +use PHPUnit\Framework\MockObject\Generator\ClassIsFinalException; +use PHPUnit\Framework\MockObject\Generator\UnknownTypeException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\Enumeration; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use PHPUnit\TestFixture\MockObject\ExtendableReadonlyClass; +use PHPUnit\TestFixture\MockObject\FinalClass; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('createStub()')] +final class CreateStubTest extends TestCase +{ + public function testCreatesTestStubForInterface(): void + { + $double = $this->createStub(AnInterface::class); + + $this->assertInstanceOf(AnInterface::class, $double); + $this->assertInstanceOf(Stub::class, $double); + } + + public function testCreatesTestStubForExtendableClass(): void + { + $double = $this->createStub(ExtendableClass::class); + + $this->assertInstanceOf(ExtendableClass::class, $double); + $this->assertInstanceOf(Stub::class, $double); + } + + public function testCreatesTestStubForExtendableReadonlyClass(): void + { + $double = $this->createStub(ExtendableReadonlyClass::class); + + $this->assertInstanceOf(ExtendableReadonlyClass::class, $double); + $this->assertInstanceOf(Stub::class, $double); + } + + public function testReturnValueGenerationIsEnabledByDefault(): void + { + $double = $this->createStub(AnInterface::class); + + $this->assertFalse($double->doSomething()); + } + + public function testCannotCreateTestStubForFinalClass(): void + { + $this->expectException(ClassIsFinalException::class); + + $this->createStub(FinalClass::class); + } + + public function testCannotCreateTestStubForEnumeration(): void + { + $this->expectException(ClassIsEnumerationException::class); + + $this->createStub(Enumeration::class); + } + + public function testCannotCreateTestStubForUnknownType(): void + { + $this->expectException(UnknownTypeException::class); + + $this->createStub('this\does\not\exist'); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/CreateStubWithDisabledReturnValueGenerationTest.php b/tests/unit/Framework/MockObject/Creation/CreateStubWithDisabledReturnValueGenerationTest.php new file mode 100644 index 00000000000..eff448ae4f7 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/CreateStubWithDisabledReturnValueGenerationTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; + +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('createStub()')] +#[DisableReturnValueGenerationForTestDoubles] +final class CreateStubWithDisabledReturnValueGenerationTest extends TestCase +{ + public function testReturnValueGenerationCanBeDisabledWithAttribute(): void + { + $double = $this->createStub(AnInterface::class); + + $this->expectException(ReturnValueNotConfiguredException::class); + + $double->doSomething(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/MockBuilderTest.php b/tests/unit/Framework/MockObject/Creation/MockBuilderTest.php new file mode 100644 index 00000000000..cd325515c36 --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/MockBuilderTest.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function md5; +use function mt_rand; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\DuplicateMethodException; +use PHPUnit\Framework\MockObject\Generator\InvalidMethodNameException; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use PHPUnit\TestFixture\MockObject\ExtendableClassCallingMethodInConstructor; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithConstructorArguments; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; + +#[CoversClass(MockBuilder::class)] +#[CoversMethod(TestCase::class, 'getMockBuilder')] +#[CoversClass(DuplicateMethodException::class)] +#[CoversClass(InvalidMethodNameException::class)] +#[CoversClass(NameAlreadyInUseException::class)] +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/mock-object')] +#[Medium] +final class MockBuilderTest extends TestCase +{ + #[TestDox('setMockClassName() can be used to configure the name of the mock object class')] + public function testCanCreateMockObjectWithSpecifiedClassName(): void + { + $className = 'random_' . md5((string) mt_rand()); + + $double = $this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class) + ->setMockClassName($className) + ->getMock(); + + $this->assertSame($className, $double::class); + } + + #[TestDox('setMockClassName() cannot be used to configure the name of the mock object class when a class with that name already exists')] + public function testCannotCreateMockObjectWithSpecifiedClassNameWhenClassWithThatNameAlreadyExists(): void + { + $this->expectException(NameAlreadyInUseException::class); + + $this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class) + ->setMockClassName(__CLASS__) + ->getMock(); + } + + #[TestDox('setConstructorArgs() can be used to configure constructor arguments for a partially mocked class')] + public function testConstructorArgumentsCanBeConfiguredForPartiallyMockedClass(): void + { + $value = 'string'; + + $double = $this->getMockBuilder(ExtendableClassWithConstructorArguments::class) + ->enableOriginalConstructor() + ->setConstructorArgs([$value]) + ->onlyMethods([]) + ->getMock(); + + $this->assertSame($value, $double->value()); + } + + #[TestDox('onlyMethods() can be used to configure which methods should be doubled')] + public function testCreatesPartialMockObjectForExtendableClass(): void + { + $double = $this->getMockBuilder(ExtendableClass::class) + ->onlyMethods(['doSomethingElse']) + ->getMock(); + + $double->expects($this->once())->method('doSomethingElse')->willReturn(true); + + $this->assertTrue($double->doSomething()); + } + + public function testDefaultBehaviourCanBeConfiguredExplicitly(): void + { + $double = $this->getMockBuilder(ExtendableClass::class) + ->enableOriginalConstructor() + ->enableOriginalClone() + ->enableAutoReturnValueGeneration() + ->getMock(); + + $this->assertTrue($double->constructorCalled); + } + + #[TestDox('Mocked methods can be called from the original constructor of a partially mocked class')] + public function testOnlyMethodCalledInConstructorWorks(): void + { + $double = $this->getMockBuilder(ExtendableClassCallingMethodInConstructor::class) + ->onlyMethods(['reset']) + ->getMock(); + + $double->expects($this->once())->method('reset'); + + $double->second(); + } +} diff --git a/tests/unit/Framework/MockObject/Creation/TestStubBuilderTest.php b/tests/unit/Framework/MockObject/Creation/TestStubBuilderTest.php new file mode 100644 index 00000000000..2e294ebb31e --- /dev/null +++ b/tests/unit/Framework/MockObject/Creation/TestStubBuilderTest.php @@ -0,0 +1,92 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function md5; +use function mt_rand; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\MockObject\Generator\NameAlreadyInUseException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithConstructorArguments; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; + +#[CoversClass(TestStubBuilder::class)] +#[CoversMethod(TestCase::class, 'getStubBuilder')] +#[Group('test-doubles')] +#[Group('test-doubles/creation')] +#[Group('test-doubles/test-stub')] +#[TestDox('TestStubBuilder')] +#[Medium] +final class TestStubBuilderTest extends TestCase +{ + #[TestDox('setStubClassName() can be used to configure the name of the test stub class')] + public function testCanCreateTestStubWithSpecifiedClassName(): void + { + $className = 'random_' . md5((string) mt_rand()); + + $double = $this->getStubBuilder(InterfaceWithReturnTypeDeclaration::class) + ->setStubClassName($className) + ->getStub(); + + $this->assertSame($className, $double::class); + } + + #[TestDox('setStubClassName() cannot be used to configure the name of the test stub class when a class with that name already exists')] + public function testCannotCreateTestStubWithSpecifiedClassNameWhenClassWithThatNameAlreadyExists(): void + { + $this->expectException(NameAlreadyInUseException::class); + + $this->getStubBuilder(InterfaceWithReturnTypeDeclaration::class) + ->setStubClassName(__CLASS__) + ->getStub(); + } + + #[TestDox('setConstructorArgs() can be used to configure constructor arguments for a partially stubbed class')] + public function testConstructorArgumentsCanBeConfiguredForPartiallyStubbedClass(): void + { + $value = 'string'; + + $double = $this->getStubBuilder(ExtendableClassWithConstructorArguments::class) + ->enableOriginalConstructor() + ->setConstructorArgs([$value]) + ->onlyMethods([]) + ->getStub(); + + $this->assertSame($value, $double->value()); + } + + #[TestDox('onlyMethods() can be used to configure which methods should be doubled')] + public function testCreatesPartialTestStubForExtendableClass(): void + { + $double = $this->getStubBuilder(ExtendableClass::class) + ->onlyMethods(['doSomethingElse']) + ->getStub(); + + $double->method('doSomethingElse')->willReturn(true); + + $this->assertTrue($double->doSomething()); + } + + public function testDefaultBehaviourCanBeConfiguredExplicitly(): void + { + $double = $this->getStubBuilder(ExtendableClass::class) + ->enableOriginalConstructor() + ->enableOriginalClone() + ->enableAutoReturnValueGeneration() + ->getStub(); + + $this->assertTrue($double->constructorCalled); + } +} diff --git a/tests/unit/Framework/MockObject/Generator/PropertyTest.php b/tests/unit/Framework/MockObject/Generator/PropertyTest.php new file mode 100644 index 00000000000..1beab059452 --- /dev/null +++ b/tests/unit/Framework/MockObject/Generator/PropertyTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Generator; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use SebastianBergmann\Type\Type; + +#[CoversClass(HookedProperty::class)] +#[Group('test-doubles')] +#[Small] +final class PropertyTest extends TestCase +{ + public function testHasName(): void + { + $name = 'property-name'; + + $property = new HookedProperty($name, Type::fromName('string', false), false, false); + + $this->assertSame($name, $property->name()); + } + + public function testHasType(): void + { + $type = Type::fromName('string', false); + + $property = new HookedProperty('property-name', $type, false, false); + + $this->assertSame($type, $property->type()); + } + + public function testMayHaveGetHook(): void + { + $property = new HookedProperty('property-name', Type::fromName('string', false), true, false); + + $this->assertTrue($property->hasGetHook()); + } + + public function testMayNotHaveGetHook(): void + { + $property = new HookedProperty('property-name', Type::fromName('string', false), false, false); + + $this->assertFalse($property->hasGetHook()); + } + + public function testMayHaveSetHook(): void + { + $property = new HookedProperty('property-name', Type::fromName('string', false), false, true); + + $this->assertTrue($property->hasSetHook()); + } + + public function testMayNotHaveSetHook(): void + { + $property = new HookedProperty('property-name', Type::fromName('string', false), false, false); + + $this->assertFalse($property->hasSetHook()); + } +} diff --git a/tests/unit/Framework/MockObject/MockObjectTest.php b/tests/unit/Framework/MockObject/MockObjectTest.php new file mode 100644 index 00000000000..9b604ba2106 --- /dev/null +++ b/tests/unit/Framework/MockObject/MockObjectTest.php @@ -0,0 +1,550 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function call_user_func_array; +use Exception; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithCloneMethod; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithPropertyWithSetHook; +use PHPUnit\TestFixture\MockObject\ExtendableReadonlyClassWithCloneMethod; +use PHPUnit\TestFixture\MockObject\InterfaceWithImplicitProtocol; +use PHPUnit\TestFixture\MockObject\InterfaceWithPropertyWithSetHook; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; +use PHPUnit\TestFixture\MockObject\MethodWIthVariadicVariables; +use ReflectionProperty; + +#[Group('test-doubles')] +#[Group('test-doubles/mock-object')] +#[TestDox('Mock Object')] +#[Medium] +final class MockObjectTest extends TestDoubleTestCase +{ + public function testExpectationThatMethodIsNeverCalledSucceedsWhenMethodIsNotCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->never())->method('doSomething'); + } + + public function testExpectationThatMethodIsNeverCalledFailsWhenMethodIsCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->never())->method('doSomething'); + + $this->assertThatMockObjectExpectationFails( + AnInterface::class . '::doSomething(): bool was not expected to be called.', + $double, + 'doSomething', + ); + } + + #[DoesNotPerformAssertions] + public function testExpectationThatMethodIsCalledZeroOrMoreTimesSucceedsWhenMethodIsNotCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->any())->method('doSomething'); + } + + #[DoesNotPerformAssertions] + public function testExpectationThatMethodIsCalledZeroOrMoreTimesSucceedsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->any())->method('doSomething'); + + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledOnceSucceedsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->once())->method('doSomething'); + + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledOnceFailsWhenMethodIsNeverCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->once())->method('doSomething'); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked 1 time. +Method was expected to be called 1 time, actually called 0 times. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledOnceFailsWhenMethodIsCalledMoreThanOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->once())->method('doSomething'); + + $double->doSomething(); + + $this->assertThatMockObjectExpectationFails( + AnInterface::class . '::doSomething(): bool was not expected to be called more than once.', + $double, + 'doSomething', + ); + } + + public function testExpectationThatMethodIsCalledAtLeastOnceSucceedsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeastOnce())->method('doSomething'); + + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledAtLeastOnceSucceedsWhenMethodIsCalledTwice(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeastOnce())->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledAtLeastTwiceSucceedsWhenMethodIsCalledTwice(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeast(2))->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledAtLeastTwiceSucceedsWhenMethodIsCalledThreeTimes(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeast(2))->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledAtLeastOnceFailsWhenMethodIsNotCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeastOnce())->method('doSomething'); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked at least once. +Expected invocation at least once but it never occurred. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledAtLeastTwiceFailsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atLeast(2))->method('doSomething'); + + $double->doSomething(); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked at least 2 times. +Expected invocation at least 2 times but it occurred 1 time. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledTwiceSucceedsWhenMethodIsCalledTwice(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->exactly(2))->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledTwiceFailsWhenMethodIsNeverCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->exactly(2))->method('doSomething'); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked 2 times. +Method was expected to be called 2 times, actually called 0 times. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledTwiceFailsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->exactly(2))->method('doSomething'); + + $double->doSomething(); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked 2 times. +Method was expected to be called 2 times, actually called 1 time. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledTwiceFailsWhenMethodIsCalledThreeTimes(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->exactly(2))->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + + $this->assertThatMockObjectExpectationFails( + AnInterface::class . '::doSomething(): bool was not expected to be called more than 2 times.', + $double, + 'doSomething', + ); + } + + public function testExpectationThatMethodIsCalledAtMostOnceSucceedsWhenMethodIsNeverCalled(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atMost(1))->method('doSomething'); + } + + public function testExpectationThatMethodIsCalledAtMostOnceSucceedsWhenMethodIsCalledOnce(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atMost(1))->method('doSomething'); + + $double->doSomething(); + } + + public function testExpectationThatMethodIsCalledAtMostOnceFailsWhenMethodIsCalledTwice(): void + { + $double = $this->createMock(AnInterface::class); + + $double->expects($this->atMost(1))->method('doSomething'); + + $double->doSomething(); + $double->doSomething(); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomething" when invoked at most 1 time. +Expected invocation at most 1 time but it occurred 2 times. + +EOT, + $double, + ); + } + + public function testExpectationThatMethodIsCalledWithAnyParameterSucceedsWhenMethodIsCalledWithParameter(): void + { + $double = $this->createMock(InterfaceWithReturnTypeDeclaration::class); + + $double->expects($this->once())->method('doSomethingElse')->withAnyParameters(); + + $double->doSomethingElse(1); + } + + public function testExpectationThatMethodIsCalledWithParameterSucceedsWhenMethodIsCalledWithExpectedParameter(): void + { + $double = $this->createMock(InterfaceWithReturnTypeDeclaration::class); + + $double->expects($this->once())->method('doSomethingElse')->with(1); + + $double->doSomethingElse(1); + } + + public function testExpectationThatMethodIsCalledWithParameterFailsWhenMethodIsCalledButWithUnexpectedParameter(): void + { + $double = $this->createMock(InterfaceWithReturnTypeDeclaration::class); + + $double->expects($this->once())->method('doSomethingElse')->with(1); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "doSomethingElse" when invoked 1 time +Parameter 0 for invocation PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration::doSomethingElse(0): int does not match expected value. +Failed asserting that 0 matches expected 1. +EOT, + $double, + 'doSomethingElse', + [0], + ); + } + + /** + * With $double->expects($this->once())->method('one')->id($id);, + * we configure an expectation that one() is called once. This expectation is given the ID $id. + * + * With $double->expects($this->once())->method('two')->after($id);, + * we configure an expectation that two() is called once. However, this expectation will only be verified + * if/after one() has been called. + */ + public function testMethodCallCanBeExpectedContingentOnWhetherAnotherMethodWasPreviouslyCalled(): void + { + $id = 'the-id'; + $double = $this->createMock(InterfaceWithImplicitProtocol::class); + + $double->expects($this->once()) + ->method('one') + ->id($id); + + $double->expects($this->once()) + ->method('two') + ->after($id); + + $double->one(); + $double->two(); + } + + public function testContingentExpectationsAreNotEvaluatedUntilTheirConditionIsMet(): void + { + $id = 'the-id'; + $double = $this->createMock(InterfaceWithImplicitProtocol::class); + + $double->expects($this->once()) + ->method('one') + ->id($id); + + $double->expects($this->once()) + ->method('two') + ->after($id); + + $double->two(); + $double->one(); + $double->two(); + } + + public function testContingentExpectationsAreEvaluatedWhenTheirConditionIsMet(): void + { + $id = 'the-id'; + $double = $this->createMock(InterfaceWithImplicitProtocol::class); + + $double->expects($this->once()) + ->method('one') + ->id($id); + + $double->expects($this->once()) + ->method('two') + ->after($id); + + $double->two(); + $double->one(); + + $this->assertThatMockObjectExpectationFails( + <<<'EOT' +Expectation failed for method name is "two" when invoked 1 time. +Method was expected to be called 1 time, actually called 0 times. + +EOT, + $double, + ); + } + + public function testExpectationCannotBeContingentOnExpectationThatHasNotBeenConfigured(): void + { + $double = $this->createMock(InterfaceWithImplicitProtocol::class); + + $double->expects($this->once()) + ->method('two') + ->after('the-id'); + + $this->assertThatMockObjectExpectationFails( + 'No builder found for match builder identification ', + $double, + 'two', + ); + } + + public function testExpectationsCannotHaveDuplicateIds(): void + { + $id = 'the-id'; + $double = $this->createMock(InterfaceWithImplicitProtocol::class); + + $double->expects($this->once()) + ->method('one') + ->id($id); + + try { + $double->expects($this->once()) + ->method('one') + ->id($id); + } catch (MatcherAlreadyRegisteredException $e) { + $this->assertSame('Matcher with id is already registered', $e->getMessage()); + + return; + } finally { + $this->resetMockObjects(); + } + + $this->fail(); + } + + public function testWillReturnCallbackWithVariadicVariables(): void + { + $double = $this->createMock(MethodWIthVariadicVariables::class); + $double->expects($this->once())->method('testVariadic') + ->withAnyParameters() + ->willReturnCallback(static fn (string $string, string ...$arguments) => [$string, ...$arguments]); + + $testData = ['foo', 'bar', 'biz' => 'kuz']; + $actual = $double->testVariadic(...$testData); + + $this->assertSame($testData, $actual); + } + + public function testExpectationsAreClonedWhenTestDoubleIsCloned(): void + { + $double = $this->createMock(InterfaceWithReturnTypeDeclaration::class); + + $double->expects($this->exactly(2))->method('doSomething'); + + $clone = clone $double; + + $double->expects($this->once())->method('doSomethingElse')->willReturn(1); + $clone->expects($this->once())->method('doSomethingElse')->willReturn(2); + + $this->assertFalse($double->doSomething()); + $this->assertFalse($clone->doSomething()); + $this->assertSame(1, $double->doSomethingElse(0)); + $this->assertSame(2, $clone->doSomethingElse(0)); + } + + #[RequiresMethod(ReflectionProperty::class, 'isFinal')] + public function testExpectationCanBeConfiguredForSetHookForPropertyOfInterface(): void + { + $double = $this->createTestDouble(InterfaceWithPropertyWithSetHook::class); + + $double->expects($this->once())->method(PropertyHook::set('property'))->with('value'); + + $double->property = 'value'; + } + + #[RequiresMethod(ReflectionProperty::class, 'isFinal')] + public function testExpectationCanBeConfiguredForSetHookForPropertyOfExtendableClass(): void + { + $double = $this->createTestDouble(ExtendableClassWithPropertyWithSetHook::class); + + $double->expects($this->once())->method(PropertyHook::set('property'))->with('value'); + + $double->property = 'value'; + } + + #[TestDox('__toString() method returns empty string when return value generation is disabled and no return value is configured')] + public function testToStringMethodReturnsEmptyStringWhenReturnValueGenerationIsDisabledAndNoReturnValueIsConfigured(): void + { + $double = $this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class) + ->disableAutoReturnValueGeneration() + ->getMock(); + + $this->assertSame('', $double->__toString()); + } + + public function testMethodDoesNotReturnValueWhenReturnValueGenerationIsDisabledAndNoReturnValueIsConfigured(): void + { + $double = $this->getMockBuilder(InterfaceWithReturnTypeDeclaration::class) + ->disableAutoReturnValueGeneration() + ->getMock(); + + $this->expectException(ReturnValueNotConfiguredException::class); + $this->expectExceptionMessage('No return value is configured for ' . InterfaceWithReturnTypeDeclaration::class . '::doSomething() and return value generation is disabled'); + + $double->doSomething(); + } + + #[TestDox('Original __clone() method can optionally be called when test double object is cloned')] + public function testOriginalCloneMethodCanOptionallyBeCalledWhenTestDoubleObjectIsCloned(): void + { + $double = $this->getMockBuilder(ExtendableClassWithCloneMethod::class)->enableOriginalClone()->getMock(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage(ExtendableClassWithCloneMethod::class . '::__clone'); + + clone $double; + } + + #[TestDox('Original __clone() method can optionally be called when test double object is cloned (readonly class)')] + public function testOriginalCloneMethodCanOptionallyBeCalledWhenTestDoubleObjectOfReadonlyClassIsCloned(): void + { + $double = $this->getMockBuilder(ExtendableReadonlyClassWithCloneMethod::class)->enableOriginalClone()->getMock(); + + $this->expectException(Exception::class); + $this->expectExceptionMessage(ExtendableReadonlyClassWithCloneMethod::class . '::__clone'); + + clone $double; + } + + /** + * @param class-string $type + */ + protected function createTestDouble(string $type): object + { + return $this->createMock($type); + } + + private function assertThatMockObjectExpectationFails(string $expectationFailureMessage, MockObject $double, string $methodName = '__phpunit_verify', array $arguments = []): void + { + try { + call_user_func_array([$double, $methodName], $arguments); + } catch (ExpectationFailedException|MatchBuilderNotFoundException $e) { + $this->assertSame($expectationFailureMessage, $e->getMessage()); + + return; + } finally { + $this->resetMockObjects(); + } + + $this->fail(); + } + + private function resetMockObjects(): void + { + new ReflectionProperty(TestCase::class, 'mockObjects')->setValue($this, []); + } +} diff --git a/tests/unit/Framework/MockObject/ReturnValueGeneratorTest.php b/tests/unit/Framework/MockObject/ReturnValueGeneratorTest.php new file mode 100644 index 00000000000..98691117cce --- /dev/null +++ b/tests/unit/Framework/MockObject/ReturnValueGeneratorTest.php @@ -0,0 +1,270 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use function sprintf; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\AnInterface; +use PHPUnit\TestFixture\MockObject\AnInterfaceForIssue5593; +use PHPUnit\TestFixture\MockObject\AnotherInterface; +use PHPUnit\TestFixture\MockObject\AnotherInterfaceForIssue5593; +use PHPUnit\TestFixture\MockObject\ExtendableClass; +use PHPUnit\TestFixture\MockObject\InterfaceWithMethodThatReturnsSelf; +use PHPUnit\TestFixture\MockObject\InterfaceWithMethodThatReturnsStatic; +use PHPUnit\TestFixture\MockObject\YetAnotherInterface; +use stdClass; + +#[CoversClass(ReturnValueGenerator::class)] +#[Group('test-doubles')] +#[Group('test-doubles/test-stub')] +#[Small] +final class ReturnValueGeneratorTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function unionProvider(): array + { + return [ + [null, 'null|true|float|int|string|array|object'], + [null, 'null|false|float|int|string|array|object'], + [null, 'null|bool|float|int|string|array|object'], + [true, 'true|float|int|string|array|object'], + [false, 'false|float|int|string|array|object'], + [false, 'bool|float|int|string|array|object'], + [0, 'int|string|array|object'], + ['', 'string|array|object'], + [[], 'array|object'], + ]; + } + + public function test_Generates_null_for_missing_return_type_declaration(): void + { + $this->assertNull($this->generate('')); + } + + public function test_Generates_null_for_null(): void + { + $this->assertNull($this->generate('null')); + } + + public function test_Generates_null_for_mixed(): void + { + $this->assertNull($this->generate('mixed')); + } + + public function test_Generates_null_for_void(): void + { + $this->assertNull($this->generate('void')); + } + + public function test_Generates_true_for_true(): void + { + $this->assertTrue($this->generate('true')); + } + + public function test_Generates_false_for_bool(): void + { + $this->assertFalse($this->generate('bool')); + } + + public function test_Generates_false_for_false(): void + { + $this->assertFalse($this->generate('false')); + } + + #[TestDox('Generates 0.0 for float')] + public function test_Generates_00_for_float(): void + { + $this->assertSame(0.0, $this->generate('float')); + } + + public function test_Generates_0_for_int(): void + { + $this->assertSame(0, $this->generate('int')); + } + + public function test_Generates_empty_string_for_string(): void + { + $this->assertSame('', $this->generate('string')); + } + + public function test_Generates_empty_array_for_array(): void + { + $this->assertSame([], $this->generate('array')); + } + + public function test_Generates_stdClass_object_for_object(): void + { + $this->assertInstanceOf(stdClass::class, $this->generate('object')); + } + + public function test_Generates_callable_for_callable(): void + { + $this->assertIsCallable($this->generate('callable')); + } + + public function test_Generates_callable_for_Closure(): void + { + $this->assertIsCallable($this->generate('Closure')); + } + + public function test_Generates_Generator_for_Generator(): void + { + $value = $this->generate('Generator'); + + $this->assertInstanceOf(Generator::class, $value); + + foreach ($value as $element) { + $this->assertSame([], $element); + } + } + + public function test_Generates_Generator_for_Traversable(): void + { + $value = $this->generate('Traversable'); + + $this->assertInstanceOf(Generator::class, $value); + + foreach ($value as $element) { + $this->assertSame([], $element); + } + } + + public function test_Generates_Generator_for_iterable(): void + { + $value = $this->generate('iterable'); + + $this->assertInstanceOf(Generator::class, $value); + + foreach ($value as $element) { + $this->assertSame([], $element); + } + } + + public function test_Generates_test_stub_for_class_or_interface_name(): void + { + $value = $this->generate(AnInterface::class); + + $this->assertInstanceOf(Stub::class, $value); + $this->assertInstanceOf(AnInterface::class, $value); + } + + public function test_Generates_test_stub_for_intersection_of_interfaces(): void + { + $value = $this->generate(AnInterface::class . '&' . AnotherInterface::class); + + $this->assertInstanceOf(Stub::class, $value); + $this->assertInstanceOf(AnInterface::class, $value); + $this->assertInstanceOf(AnotherInterface::class, $value); + } + + public function test_Generates_new_instance_of_test_stub_for_self(): void + { + $stub = $this->createStub(InterfaceWithMethodThatReturnsSelf::class); + + $returnValue = $stub->doSomething(); + + $this->assertNotInstanceOf($stub::class, $returnValue); + $this->assertNotSame($stub, $returnValue); + } + + public function test_Generates_new_instance_of_test_stub_for_static(): void + { + $stub = $this->createStub(InterfaceWithMethodThatReturnsStatic::class); + + $returnValue = $stub->doSomething(); + + $this->assertInstanceOf($stub::class, $returnValue); + $this->assertNotSame($stub, $returnValue); + } + + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/5593')] + public function test_Generates_new_instance_of_test_stub_for_static_when_used_recursively(): void + { + $a = $this->createStub(AnInterfaceForIssue5593::class); + + $this->assertInstanceOf(AnInterfaceForIssue5593::class, $a); + + $b = $a->doSomething(); + + $this->assertInstanceOf(AnotherInterfaceForIssue5593::class, $b); + + $c = $b->doSomethingElse(); + + $this->assertInstanceOf(AnotherInterfaceForIssue5593::class, $c); + } + + #[DataProvider('unionProvider')] + #[TestDox('Generates $expected for $union')] + public function test_Generates_return_value_for_union(mixed $expected, string $union): void + { + $this->assertSame($expected, $this->generate($union)); + } + + public function test_Generates_stdClass_object_for_union_that_contains_object_and_unknown_type(): void + { + $this->assertInstanceOf(stdClass::class, $this->generate('object|ThisDoesNotExist')); + } + + public function test_Generates_test_stub_for_first_intersection_of_interfaces_found_in_union_of_intersections(): void + { + $value = $this->generate( + sprintf( + '(%s&%s)|(%s&%s)', + AnInterface::class, + AnotherInterface::class, + AnInterface::class, + YetAnotherInterface::class, + ), + ); + + $this->assertInstanceOf(Stub::class, $value); + $this->assertInstanceOf(AnInterface::class, $value); + $this->assertInstanceOf(AnotherInterface::class, $value); + } + + public function test_Does_not_handle_union_of_extendable_class_and_interface(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Return value for OriginalClassName::methodName() cannot be generated because the declared return type is a union, please configure a return value for this method'); + + $this->generate(ExtendableClass::class . '|' . AnInterface::class); + } + + public function test_Does_not_handle_intersection_of_extendable_class_and_interface(): void + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Return value for OriginalClassName::methodName() cannot be generated because the declared return type is an intersection, please configure a return value for this method'); + + $this->generate(ExtendableClass::class . '&' . AnInterface::class); + } + + private function generate(string $typeDeclaration, ?StubInternal $testStub = null): mixed + { + if ($testStub === null) { + $testStub = $this->createStub(AnInterface::class); + } + + return (new ReturnValueGenerator)->generate( + 'OriginalClassName', + 'methodName', + $testStub, + $typeDeclaration, + ); + } +} diff --git a/tests/unit/Framework/MockObject/Runtime/PropertyGetHookTest.php b/tests/unit/Framework/MockObject/Runtime/PropertyGetHookTest.php new file mode 100644 index 00000000000..3ef9b5616fb --- /dev/null +++ b/tests/unit/Framework/MockObject/Runtime/PropertyGetHookTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(PropertyHook::class)] +#[CoversClass(PropertyGetHook::class)] +#[Small] +#[Group('test-doubles')] +final class PropertyGetHookTest extends TestCase +{ + public function testHasPropertyName(): void + { + $propertyName = 'property'; + + $propertyHook = PropertyHook::get($propertyName); + + $this->assertSame($propertyName, $propertyHook->propertyName()); + } + + public function testCanBeRepresentedAsString(): void + { + $propertyName = 'property'; + + $propertyHook = PropertyHook::get($propertyName); + + $this->assertSame('$' . $propertyName . '::get', $propertyHook->asString()); + } +} diff --git a/tests/unit/Framework/MockObject/Runtime/PropertySetHookTest.php b/tests/unit/Framework/MockObject/Runtime/PropertySetHookTest.php new file mode 100644 index 00000000000..57c9c49961d --- /dev/null +++ b/tests/unit/Framework/MockObject/Runtime/PropertySetHookTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject\Runtime; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(PropertyHook::class)] +#[CoversClass(PropertySetHook::class)] +#[Small] +#[Group('test-doubles')] +final class PropertySetHookTest extends TestCase +{ + public function testHasPropertyName(): void + { + $propertyName = 'property'; + + $propertyHook = PropertyHook::set($propertyName); + + $this->assertSame($propertyName, $propertyHook->propertyName()); + } + + public function testCanBeRepresentedAsString(): void + { + $propertyName = 'property'; + + $propertyHook = PropertyHook::set($propertyName); + + $this->assertSame('$' . $propertyName . '::set', $propertyHook->asString()); + } +} diff --git a/tests/unit/Framework/MockObject/StubTest.php b/tests/unit/Framework/MockObject/StubTest.php new file mode 100644 index 00000000000..747fcd0e392 --- /dev/null +++ b/tests/unit/Framework/MockObject/StubTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\TestDox; + +#[Group('test-doubles')] +#[Group('test-doubles/test-stub')] +#[Medium] +#[TestDox('Test Stub')] +final class StubTest extends TestDoubleTestCase +{ + /** + * @param class-string $type + */ + protected function createTestDouble(string $type): object + { + return $this->createStub($type); + } +} diff --git a/tests/unit/Framework/MockObject/TestDoubleTestCase.php b/tests/unit/Framework/MockObject/TestDoubleTestCase.php new file mode 100644 index 00000000000..ba465c40df4 --- /dev/null +++ b/tests/unit/Framework/MockObject/TestDoubleTestCase.php @@ -0,0 +1,324 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\MockObject; + +use Exception; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\MockObject\Runtime\PropertyHook; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\MockObject\ExtendableClassCallingMethodInDestructor; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithCloneMethod; +use PHPUnit\TestFixture\MockObject\ExtendableClassWithPropertyWithGetHook; +use PHPUnit\TestFixture\MockObject\ExtendableReadonlyClassWithCloneMethod; +use PHPUnit\TestFixture\MockObject\InterfaceWithMethodThatHasDefaultParameterValues; +use PHPUnit\TestFixture\MockObject\InterfaceWithNeverReturningMethod; +use PHPUnit\TestFixture\MockObject\InterfaceWithPropertyWithGetHook; +use PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration; +use PHPUnit\TestFixture\MockObject\Issue6174; + +abstract class TestDoubleTestCase extends TestCase +{ + final public function testMethodReturnsNullWhenReturnValueIsNullableAndNoReturnValueIsConfigured(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $this->assertNull($double->returnsNullOrString()); + } + + final public function testMethodReturnsGeneratedValueWhenReturnValueGenerationIsEnabledAndNoReturnValueIsConfigured(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $this->assertFalse($double->doSomething()); + } + + final public function testMethodReturnsConfiguredValueWhenReturnValueIsConfigured(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willReturn(true); + + $this->assertTrue($double->doSomething()); + } + + final public function testConfiguredReturnValueMustBeCompatibleWithReturnTypeDeclaration(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $this->expectException(IncompatibleReturnValueException::class); + + $double->method('doSomething')->willReturn(null); + } + + final public function testMethodCanBeConfiguredToReturnOneOfItsArguments(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomethingElse')->willReturnArgument(0); + + $this->assertSame(123, $double->doSomethingElse(123)); + } + + final public function testMethodCanBeConfiguredToReturnSelfReference(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('selfReference')->willReturnSelf(); + + $this->assertSame($double, $double->selfReference()); + } + + final public function testMethodCanBeConfiguredToReturnReference(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willReturnReference($value); + + $value = true; + + $this->assertSame($value, $double->doSomething()); + } + + final public function testMethodCanBeConfiguredToReturnValuesBasedOnArgumentMapping(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomethingElse')->willReturnMap([[1, 2], [3, 4]]); + + $this->assertSame(2, $double->doSomethingElse(1)); + $this->assertSame(4, $double->doSomethingElse(3)); + } + + final public function testMethodWithDefaultParameterValuesCanBeConfiguredToReturnValuesBasedOnArgumentMapping(): void + { + $double = $this->createTestDouble(InterfaceWithMethodThatHasDefaultParameterValues::class); + + $double->method('doSomething')->willReturnMap([[1, 2, 3], [4, 5, 6]]); + + $this->assertSame(3, $double->doSomething(1, 2)); + $this->assertSame(6, $double->doSomething(4, 5)); + } + + final public function testMethodWithDefaultParameterValuesCanBeConfiguredToReturnValuesBasedOnArgumentMappingThatOmitsDefaultValues(): void + { + $double = $this->createTestDouble(InterfaceWithMethodThatHasDefaultParameterValues::class); + + $double->method('doSomething')->willReturnMap([[1, 2], [3, 4]]); + + $this->assertSame(2, $double->doSomething(1)); + $this->assertSame(4, $double->doSomething(3)); + } + + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/6174')] + final public function testIssue6174(): void + { + $double = $this->createTestDouble(Issue6174::class); + + $double->method('methodNullDefault')->willReturnMap( + [ + ['A', null, 'result'], + ], + ); + + $this->assertSame('result', $double->methodNullDefault('A')); + + $double = $this->createTestDouble(Issue6174::class); + + $double->method('methodNullDefault')->willReturnMap( + [ + ['A', 'result'], + ], + ); + + $this->assertSame('result', $double->methodNullDefault('A')); + + $double = $this->createTestDouble(Issue6174::class); + + $double->method('methodStringDefault')->willReturnMap( + [ + ['A', 'result'], + ], + ); + + $this->assertSame('result', $double->methodStringDefault('A')); + + $double = $this->createTestDouble(Issue6174::class); + + $double->method('methodStringDefault')->willReturnMap( + [ + [null, 'result'], + ], + ); + + $this->assertSame('result', $double->methodStringDefault(null)); + } + + final public function testMethodCanBeConfiguredToReturnValuesUsingCallback(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomethingElse')->willReturnCallback( + static function (int $x) + { + return match ($x) { + 1 => 2, + 3 => 4, + }; + }, + ); + + $this->assertSame(2, $double->doSomethingElse(1)); + $this->assertSame(4, $double->doSomethingElse(3)); + } + + final public function testMethodCanBeConfiguredToReturnDifferentValuesOnConsecutiveCalls(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willReturn(false, true, false, true); + + $this->assertFalse($double->doSomething()); + $this->assertTrue($double->doSomething()); + $this->assertFalse($double->doSomething()); + $this->assertTrue($double->doSomething()); + } + + final public function testMethodConfiguredToReturnDifferentValuesOnConsecutiveCallsCannotBeCalledMoreOftenThanReturnValuesHaveBeenConfigured(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willReturn(false, true); + + $this->assertFalse($double->doSomething()); + $this->assertTrue($double->doSomething()); + + $this->expectException(NoMoreReturnValuesConfiguredException::class); + $this->expectExceptionMessage('Only 2 return values have been configured for PHPUnit\TestFixture\MockObject\InterfaceWithReturnTypeDeclaration::doSomething()'); + + $double->doSomething(); + } + + final public function testMethodCanBeConfiguredToReturnDifferentValuesAndThrowExceptionsOnConsecutiveCalls(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willReturnOnConsecutiveCalls( + false, + true, + $this->throwException(new Exception), + ); + + $this->assertFalse($double->doSomething()); + $this->assertTrue($double->doSomething()); + + $this->expectException(Exception::class); + + $double->doSomething(); + } + + final public function testMethodCanBeConfiguredToThrowAnException(): void + { + $expectedException = new Exception('exception configured using throwException()'); + + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $double->method('doSomething')->willThrowException($expectedException); + + try { + $double->doSomething(); + } catch (Exception $actualException) { + $this->assertSame($expectedException, $actualException); + + return; + } + + $this->fail(); + } + + final public function testMethodWithNeverReturnTypeDeclarationThrowsException(): void + { + $double = $this->createTestDouble(InterfaceWithNeverReturningMethod::class); + + $this->expectException(NeverReturningMethodException::class); + $this->expectExceptionMessage('Method PHPUnit\TestFixture\MockObject\InterfaceWithNeverReturningMethod::m() is declared to never return'); + + $double->m(); + } + + #[TestDox('Original __clone() method is not called by default when test double object is cloned')] + final public function testOriginalCloneMethodIsNotCalledByDefaultWhenTestDoubleObjectIsCloned(): void + { + $double = clone $this->createTestDouble(ExtendableClassWithCloneMethod::class); + + $this->assertFalse($double->doSomething()); + } + + #[TestDox('Original __clone() method is not called by default when test double object is cloned (readonly class)')] + final public function testOriginalCloneMethodIsNotCalledByDefaultWhenTestDoubleObjectOfReadonlyClassIsCloned(): void + { + $double = clone $this->createTestDouble(ExtendableReadonlyClassWithCloneMethod::class); + + $this->assertFalse($double->doSomething()); + } + + public function testMethodNameCanOnlyBeConfiguredOnce(): void + { + $double = $this->createTestDouble(InterfaceWithReturnTypeDeclaration::class); + + $this->expectException(MethodNameAlreadyConfiguredException::class); + + $double + ->method('doSomething') + ->method('doSomething') + ->willReturn(true); + } + + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/5874')] + public function testDoubledMethodsCanBeCalledFromDestructorOnTestDoubleCreatedByTheReturnValueGenerator(): void + { + $double = $this->createTestDouble(ExtendableClassCallingMethodInDestructor::class); + + $this->assertInstanceOf( + ExtendableClassCallingMethodInDestructor::class, + $double->doSomething(), + ); + } + + #[RequiresPhp('^8.4')] + public function testGetHookForPropertyOfInterfaceCanBeConfigured(): void + { + $double = $this->createTestDouble(InterfaceWithPropertyWithGetHook::class); + + $double->method(PropertyHook::get('property'))->willReturn('value'); + + $this->assertSame('value', $double->property); + } + + #[RequiresPhp('^8.4')] + public function testGetHookForPropertyOfExtendableClassCanBeConfigured(): void + { + $double = $this->createTestDouble(ExtendableClassWithPropertyWithGetHook::class); + + $double->method(PropertyHook::get('property'))->willReturn('value'); + + $this->assertSame('value', $double->property); + } + + /** + * @template RealInstanceType of object + * + * @param class-string $type + * + * @return (MockObject|Stub)&RealInstanceType + */ + abstract protected function createTestDouble(string $type): object; +} diff --git a/tests/unit/Framework/TestBuilderTest.php b/tests/unit/Framework/TestBuilderTest.php new file mode 100644 index 00000000000..61e55b40863 --- /dev/null +++ b/tests/unit/Framework/TestBuilderTest.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function iterator_to_array; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\TestFixture\TestBuilder\TestWithClassLevelIsolationAttributes; +use PHPUnit\TestFixture\TestBuilder\TestWithDataProvider; +use PHPUnit\TestFixture\TestBuilder\TestWithMethodLevelIsolationAttributes; +use PHPUnit\TestFixture\TestBuilder\TestWithoutIsolationAttributes; +use ReflectionClass; + +#[CoversClass(TestBuilder::class)] +#[Small] +final class TestBuilderTest extends TestCase +{ + public function testBuildsTestWithoutMetadataForIsolation(): void + { + $test = (new TestBuilder)->build( + new ReflectionClass(TestWithoutIsolationAttributes::class), + 'testOne', + ); + + $this->assertInstanceOf(TestWithoutIsolationAttributes::class, $test); + + $test = $test->valueObjectForEvents(); + + $this->assertSame(TestWithoutIsolationAttributes::class, $test->className()); + $this->assertSame('testOne', $test->methodName()); + $this->assertTrue($test->metadata()->isBackupGlobals()->isEmpty()); + $this->assertTrue($test->metadata()->isBackupStaticProperties()->isEmpty()); + $this->assertTrue($test->metadata()->isRunTestsInSeparateProcesses()->isEmpty()); + } + + public function testBuildsTestWithClassLevelMetadataForIsolation(): void + { + $test = (new TestBuilder)->build( + new ReflectionClass(TestWithClassLevelIsolationAttributes::class), + 'testOne', + ); + + $this->assertInstanceOf(TestWithClassLevelIsolationAttributes::class, $test); + + $test = $test->valueObjectForEvents(); + + $this->assertSame(TestWithClassLevelIsolationAttributes::class, $test->className()); + $this->assertSame('testOne', $test->methodName()); + $this->assertTrue($test->metadata()->isBackupGlobals()->asArray()[0]->enabled()); + $this->assertTrue($test->metadata()->isBackupStaticProperties()->asArray()[0]->enabled()); + $this->assertTrue($test->metadata()->isRunTestsInSeparateProcesses()->isNotEmpty()); + } + + public function testBuildsTestWithMethodLevelMetadataForIsolation(): void + { + $test = (new TestBuilder)->build( + new ReflectionClass(TestWithMethodLevelIsolationAttributes::class), + 'testOne', + ); + + $this->assertInstanceOf(TestWithMethodLevelIsolationAttributes::class, $test); + + $test = $test->valueObjectForEvents(); + + $this->assertSame(TestWithMethodLevelIsolationAttributes::class, $test->className()); + $this->assertSame('testOne', $test->methodName()); + $this->assertTrue($test->metadata()->isBackupGlobals()->asArray()[0]->enabled()); + $this->assertTrue($test->metadata()->isBackupStaticProperties()->asArray()[0]->enabled()); + $this->assertTrue($test->metadata()->isRunInSeparateProcess()->isNotEmpty()); + } + + public function testBuildsTestWithDataProvider(): void + { + $test = (new TestBuilder)->build( + new ReflectionClass(TestWithDataProvider::class), + 'testOne', + ); + + $this->assertInstanceOf(DataProviderTestSuite::class, $test); + + $test = iterator_to_array($test)[0]; + + $this->assertInstanceOf(TestWithDataProvider::class, $test); + + $test = $test->valueObjectForEvents(); + + $this->assertSame(TestWithDataProvider::class, $test->className()); + $this->assertSame('testOne', $test->methodName()); + $this->assertTrue($test->testData()->hasDataFromDataProvider()); + } +} diff --git a/tests/unit/Framework/TestCaseTest.php b/tests/unit/Framework/TestCaseTest.php new file mode 100644 index 00000000000..ad8631e0199 --- /dev/null +++ b/tests/unit/Framework/TestCaseTest.php @@ -0,0 +1,105 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use function sprintf; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup; +use PHPUnit\TestFixture\TestWithDifferentNames; + +#[CoversClass(TestCase::class)] +#[ExcludeGlobalVariableFromBackup('i')] +#[ExcludeGlobalVariableFromBackup('singleton')] +class TestCaseTest extends TestCase +{ + protected static int $testStatic = 456; + + public static function provideDataSetAsStringWithDataProvider(): iterable + { + yield ['', 'dataSet', []]; + + yield ["#0 with data ('foo', 'bar')", 0, ['foo', 'bar']]; + + yield ["@dataSet with data ('foo', 'bar')", 'dataSet', ['foo', 'bar']]; + } + + public static function setUpBeforeClass(): void + { + $GLOBALS['a'] = 'a'; + $_ENV['b'] = 'b'; + $_POST['c'] = 'c'; + $_GET['d'] = 'd'; + $_COOKIE['e'] = 'e'; + $_SERVER['f'] = 'f'; + $_FILES['g'] = 'g'; + $_REQUEST['h'] = 'h'; + $GLOBALS['i'] = 'i'; + } + + public static function tearDownAfterClass(): void + { + unset( + $GLOBALS['a'], + $_ENV['b'], + $_POST['c'], + $_GET['d'], + $_COOKIE['e'], + $_SERVER['f'], + $_FILES['g'], + $_REQUEST['h'], + $GLOBALS['i'], + ); + } + + public function testCaseToString(): void + { + $this->assertEquals( + sprintf( + '%s::testCaseToString', + self::class, + ), + $this->toString(), + ); + } + + public function testCaseDefaultExecutionOrderDependencies(): void + { + $this->assertInstanceOf(Reorderable::class, $this); + + $this->assertEquals( + [new ExecutionOrderDependency(static::class, 'testCaseDefaultExecutionOrderDependencies')], + $this->provides(), + ); + + $this->assertEquals( + [], + $this->requires(), + ); + } + + public function testGetNameReturnsMethodName(): void + { + $methodName = 'testWithName'; + + $testCase = new TestWithDifferentNames($methodName); + + $this->assertSame($methodName, $testCase->nameWithDataSet()); + } + + #[DataProvider('provideDataSetAsStringWithDataProvider')] + public function testDataSetAsStringWithData(string $expectedData, int|string $dataName, array $data): void + { + $testCase = new TestWithDifferentNames('testWithName'); + $testCase->setData($dataName, $data); + + $this->assertSame($expectedData, $testCase->dataSetAsStringWithData()); + } +} diff --git a/tests/unit/Framework/TestRunner/ChildProcessResultProcessorTest.php b/tests/unit/Framework/TestRunner/ChildProcessResultProcessorTest.php new file mode 100644 index 00000000000..ee64fd34aab --- /dev/null +++ b/tests/unit/Framework/TestRunner/ChildProcessResultProcessorTest.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Event\Emitter; +use PHPUnit\Event\Facade; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestFixture\Success; +use PHPUnit\TestRunner\TestResult\PassedTests; + +#[CoversClass(ChildProcessResultProcessor::class)] +#[Small] +final class ChildProcessResultProcessorTest extends TestCase +{ + #[TestDox('Emits Test\Errored event when standard output is not empty')] + public function testEmitsErrorEventWhenStderrIsNotEmpty(): void + { + $emitter = $this->createMock(Emitter::class); + + $emitter + ->expects($this->once()) + ->method('testErrored'); + + $this->processor($emitter)->process(new Success('testOne'), '', 'error'); + } + + #[TestDox('Emits Test\Errored event when process result cannot be unserialized')] + public function testEmitsErrorEventWhenProcessResultCannotBeUnserialized(): void + { + $emitter = $this->createMock(Emitter::class); + + $emitter + ->expects($this->once()) + ->method('testErrored'); + + $this->processor($emitter)->process(new Success('testOne'), '', ''); + } + + private function processor(Emitter $emitter): ChildProcessResultProcessor + { + return new ChildProcessResultProcessor( + new Facade, + $emitter, + new PassedTests, + new CodeCoverage, + ); + } +} diff --git a/tests/unit/Framework/TestSizeTest.php b/tests/unit/Framework/TestSizeTest.php new file mode 100644 index 00000000000..4632c66bb2b --- /dev/null +++ b/tests/unit/Framework/TestSizeTest.php @@ -0,0 +1,139 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestSize; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestSize::class)] +#[CoversClassesThatExtendClass(TestSize::class)] +#[Small] +final class TestSizeTest extends TestCase +{ + public static function comparisonProvider(): array + { + return [ + 'small test is not greater than small test' => [ + false, + TestSize::small(), + TestSize::small(), + ], + + 'small test is not greater than medium test' => [ + false, + TestSize::small(), + TestSize::medium(), + ], + + 'small test is not greater than large test' => [ + false, + TestSize::small(), + TestSize::large(), + ], + + 'medium test is greater than small test' => [ + true, + TestSize::medium(), + TestSize::small(), + ], + + 'medium test is not greater than medium test' => [ + false, + TestSize::medium(), + TestSize::medium(), + ], + + 'medium test is not greater than large test' => [ + false, + TestSize::medium(), + TestSize::large(), + ], + + 'large test is greater than small test' => [ + true, + TestSize::large(), + TestSize::small(), + ], + + 'large test is greater than medium test' => [ + true, + TestSize::large(), + TestSize::medium(), + ], + + 'large test is not greater than large test' => [ + false, + TestSize::large(), + TestSize::large(), + ], + ]; + } + + public function testCanBeUnknown(): void + { + $testSize = TestSize::unknown(); + + $this->assertFalse($testSize->isKnown()); + $this->assertTrue($testSize->isUnknown()); + $this->assertFalse($testSize->isSmall()); + $this->assertFalse($testSize->isMedium()); + $this->assertFalse($testSize->isLarge()); + + $this->assertSame('unknown', $testSize->asString()); + } + + public function testCanBeSmall(): void + { + $testSize = TestSize::small(); + + $this->assertTrue($testSize->isKnown()); + $this->assertFalse($testSize->isUnknown()); + $this->assertTrue($testSize->isSmall()); + $this->assertFalse($testSize->isMedium()); + $this->assertFalse($testSize->isLarge()); + + $this->assertSame('small', $testSize->asString()); + } + + public function testCanBeMedium(): void + { + $testSize = TestSize::medium(); + + $this->assertTrue($testSize->isKnown()); + $this->assertFalse($testSize->isUnknown()); + $this->assertFalse($testSize->isSmall()); + $this->assertTrue($testSize->isMedium()); + $this->assertFalse($testSize->isLarge()); + + $this->assertSame('medium', $testSize->asString()); + } + + public function testCanBeLarge(): void + { + $testSize = TestSize::large(); + + $this->assertTrue($testSize->isKnown()); + $this->assertFalse($testSize->isUnknown()); + $this->assertFalse($testSize->isSmall()); + $this->assertFalse($testSize->isMedium()); + $this->assertTrue($testSize->isLarge()); + + $this->assertSame('large', $testSize->asString()); + } + + #[DataProvider('comparisonProvider')] + public function testTwoKnownSizesCanBeCompared(bool $expected, Known $a, Known $b): void + { + $this->assertSame($expected, $a->isGreaterThan($b)); + } +} diff --git a/tests/unit/Framework/TestStatusTest.php b/tests/unit/Framework/TestStatusTest.php new file mode 100644 index 00000000000..583c71adf90 --- /dev/null +++ b/tests/unit/Framework/TestStatusTest.php @@ -0,0 +1,289 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework\TestStatus; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestStatus::class)] +#[CoversClassesThatExtendClass(TestStatus::class)] +#[Small] +final class TestStatusTest extends TestCase +{ + public function testCanBeUnknown(): void + { + $status = TestStatus::unknown(); + + $this->assertFalse($status->isKnown()); + $this->assertTrue($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('unknown', $status->asString()); + } + + public function testCanBeSuccess(): void + { + $status = TestStatus::success(); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertTrue($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('success', $status->asString()); + } + + public function testCanBeFailure(): void + { + $status = TestStatus::failure('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertTrue($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('failure', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeError(): void + { + $status = TestStatus::error('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertTrue($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('error', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeWarning(): void + { + $status = TestStatus::warning('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertTrue($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('warning', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeRisky(): void + { + $status = TestStatus::risky('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertTrue($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('risky', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeIncomplete(): void + { + $status = TestStatus::incomplete('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertTrue($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('incomplete', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeSkipped(): void + { + $status = TestStatus::skipped('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertTrue($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('skipped', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeDeprecation(): void + { + $status = TestStatus::deprecation('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertTrue($status->isDeprecation()); + $this->assertFalse($status->isNotice()); + + $this->assertSame('deprecation', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeNotice(): void + { + $status = TestStatus::notice('message'); + + $this->assertTrue($status->isKnown()); + $this->assertFalse($status->isUnknown()); + $this->assertFalse($status->isSuccess()); + $this->assertFalse($status->isFailure()); + $this->assertFalse($status->isError()); + $this->assertFalse($status->isWarning()); + $this->assertFalse($status->isRisky()); + $this->assertFalse($status->isIncomplete()); + $this->assertFalse($status->isSkipped()); + $this->assertFalse($status->isDeprecation()); + $this->assertTrue($status->isNotice()); + + $this->assertSame('notice', $status->asString()); + $this->assertSame('message', $status->message()); + } + + public function testCanBeRepresentedAsIntegerValue(): void + { + $this->assertSame(-1, TestStatus::unknown()->asInt()); + $this->assertSame(0, TestStatus::success()->asInt()); + $this->assertSame(1, TestStatus::skipped()->asInt()); + $this->assertSame(2, TestStatus::incomplete()->asInt()); + $this->assertSame(3, TestStatus::notice()->asInt()); + $this->assertSame(4, TestStatus::deprecation()->asInt()); + $this->assertSame(5, TestStatus::risky()->asInt()); + $this->assertSame(6, TestStatus::warning()->asInt()); + $this->assertSame(7, TestStatus::failure()->asInt()); + $this->assertSame(8, TestStatus::error()->asInt()); + } + + public function testCanBeCreatedFromIntegerValue(): void + { + $this->assertInstanceOf(Unknown::class, TestStatus::from(-1)); + $this->assertInstanceOf(Success::class, TestStatus::from(0)); + $this->assertInstanceOf(Skipped::class, TestStatus::from(1)); + $this->assertInstanceOf(Incomplete::class, TestStatus::from(2)); + $this->assertInstanceOf(Notice::class, TestStatus::from(3)); + $this->assertInstanceOf(Deprecation::class, TestStatus::from(4)); + $this->assertInstanceOf(Risky::class, TestStatus::from(5)); + $this->assertInstanceOf(Warning::class, TestStatus::from(6)); + $this->assertInstanceOf(Failure::class, TestStatus::from(7)); + $this->assertInstanceOf(Error::class, TestStatus::from(8)); + } + + public function testSuccessIsMoreImportantThanUnknown(): void + { + $this->assertTrue(TestStatus::success()->isMoreImportantThan(TestStatus::unknown())); + $this->assertFalse(TestStatus::unknown()->isMoreImportantThan(TestStatus::success())); + } + + public function testSkippedIsMoreImportantThanSuccess(): void + { + $this->assertTrue(TestStatus::skipped()->isMoreImportantThan(TestStatus::success())); + $this->assertFalse(TestStatus::success()->isMoreImportantThan(TestStatus::skipped())); + } + + public function testIncompleteIsMoreImportantThanSkipped(): void + { + $this->assertTrue(TestStatus::incomplete()->isMoreImportantThan(TestStatus::skipped())); + $this->assertFalse(TestStatus::skipped()->isMoreImportantThan(TestStatus::incomplete())); + } + + public function testRiskyIsMoreImportantThanIncomplete(): void + { + $this->assertTrue(TestStatus::risky()->isMoreImportantThan(TestStatus::incomplete())); + $this->assertFalse(TestStatus::incomplete()->isMoreImportantThan(TestStatus::risky())); + } + + public function testWarningIsMoreImportantThanRisky(): void + { + $this->assertTrue(TestStatus::warning()->isMoreImportantThan(TestStatus::risky())); + $this->assertFalse(TestStatus::risky()->isMoreImportantThan(TestStatus::warning())); + } + + public function testFailureIsMoreImportantThanWarning(): void + { + $this->assertTrue(TestStatus::failure()->isMoreImportantThan(TestStatus::warning())); + $this->assertFalse(TestStatus::warning()->isMoreImportantThan(TestStatus::failure())); + } + + public function testErrorIsMoreImportantThanFailure(): void + { + $this->assertTrue(TestStatus::error()->isMoreImportantThan(TestStatus::failure())); + $this->assertFalse(TestStatus::failure()->isMoreImportantThan(TestStatus::error())); + } +} diff --git a/tests/unit/Framework/TestSuiteIteratorTest.php b/tests/unit/Framework/TestSuiteIteratorTest.php new file mode 100644 index 00000000000..813a82a020d --- /dev/null +++ b/tests/unit/Framework/TestSuiteIteratorTest.php @@ -0,0 +1,168 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\TestFixture\Success; + +#[CoversClass(TestSuiteIterator::class)] +#[Small] +final class TestSuiteIteratorTest extends TestCase +{ + public function testKeyForEmptyTestSuiteInitiallyReturnsZero(): void + { + $testSuite = TestSuite::empty('test suite name'); + $subject = new TestSuiteIterator($testSuite); + + $this->assertSame(0, $subject->key()); + } + + public function testValidForEmptyTestSuiteInitiallyReturnsFalse(): void + { + $testSuite = TestSuite::empty('test suite name'); + $subject = new TestSuiteIterator($testSuite); + + $this->assertFalse($subject->valid()); + } + + public function testKeyForNonEmptyTestSuiteInitiallyReturnsZero(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $this->assertSame(0, $subject->key()); + } + + public function testValidForNonEmptyTestSuiteInitiallyReturnsTrue(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $this->assertTrue($subject->valid()); + } + + public function testCurrentForNonEmptyTestSuiteInitiallyReturnsFirstTest(): void + { + $test = new Success('testOne'); + $testSuite = TestSuite::empty('test suite name'); + $testSuite->addTest($test); + $subject = new TestSuiteIterator($testSuite); + + $this->assertSame($test, $subject->current()); + } + + public function testRewindResetsKeyToZero(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $subject->next(); + $subject->rewind(); + + $this->assertSame(0, $subject->key()); + } + + public function testRewindResetsCurrentToFirstElement(): void + { + $testSuite = TestSuite::empty('test suite name'); + $test = new Success('testOne'); + $testSuite->addTest($test); + $subject = new TestSuiteIterator($testSuite); + $subject->next(); + + $subject->rewind(); + + $this->assertSame($test, $subject->current()); + } + + public function testNextIncreasesKeyFromZeroToOne(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $subject->next(); + + $this->assertSame(1, $subject->key()); + } + + public function testValidAfterLastElementReturnsFalse(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $subject->next(); + + $this->assertFalse($subject->valid()); + } + + public function testGetChildrenForEmptyTestSuiteThrowsException(): void + { + $subject = new TestSuiteIterator(TestSuite::empty('test suite name')); + + $this->expectException(NoChildTestSuiteException::class); + + $subject->getChildren(); + } + + public function testGetChildrenForCurrentTestThrowsException(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $this->expectException(NoChildTestSuiteException::class); + + $subject->getChildren(); + } + + public function testGetChildrenReturnsNewInstanceWithCurrentTestSuite(): void + { + $childSuite = TestSuite::empty('test suite name'); + $test = new Success('testOne'); + $childSuite->addTest($test); + + $testSuite = TestSuite::empty('test suite name'); + $testSuite->addTest($childSuite); + + $subject = new TestSuiteIterator($testSuite); + + $children = $subject->getChildren(); + + $this->assertNotSame($subject, $children); + $this->assertSame($test, $children->current()); + } + + public function testHasChildrenForCurrentTestSuiteReturnsTrue(): void + { + $testSuite = TestSuite::empty('test suite name'); + $childSuite = TestSuite::empty('test suite name'); + $testSuite->addTest($childSuite); + $subject = new TestSuiteIterator($testSuite); + + $this->assertTrue($subject->hasChildren()); + } + + public function testHasChildrenForCurrentTestReturnsFalse(): void + { + $subject = new TestSuiteIterator($this->suiteWithEmptyTestCase()); + + $this->assertFalse($subject->hasChildren()); + } + + public function testHasChildrenForNoTestsReturnsFalse(): void + { + $subject = new TestSuiteIterator(TestSuite::empty('test suite name')); + + $this->assertFalse($subject->hasChildren()); + } + + private function suiteWithEmptyTestCase(): TestSuite + { + $suite = TestSuite::empty('test suite name'); + + $suite->addTest(new Success('testOne')); + + return $suite; + } +} diff --git a/tests/unit/Framework/TestSuiteTest.php b/tests/unit/Framework/TestSuiteTest.php new file mode 100644 index 00000000000..bb90995cf40 --- /dev/null +++ b/tests/unit/Framework/TestSuiteTest.php @@ -0,0 +1,136 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Framework; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\TestFixture\AbstractTestCase; +use PHPUnit\TestFixture\DependencyFailureTest; +use PHPUnit\TestFixture\DependencyOnClassTest; +use PHPUnit\TestFixture\DependencySuccessTest; +use PHPUnit\TestFixture\MultiDependencyTest; +use PHPUnit\TestFixture\NoTestCase; +use PHPUnit\TestFixture\NotPublicTestCase; +use ReflectionClass; + +#[CoversClass(TestSuite::class)] +#[Small] +final class TestSuiteTest extends TestCase +{ + public function testNotPublicTestCase(): void + { + $suite = TestSuite::fromClassReflector(new ReflectionClass(NotPublicTestCase::class)); + + $this->assertCount(1, $suite); + } + + public function testNormalizeProvidedDependencies(): void + { + $suite = TestSuite::fromClassReflector(new ReflectionClass(MultiDependencyTest::class)); + + $this->assertEquals([ + MultiDependencyTest::class . '::class', + MultiDependencyTest::class . '::testOne', + MultiDependencyTest::class . '::testTwo', + MultiDependencyTest::class . '::testThree', + MultiDependencyTest::class . '::testFour', + MultiDependencyTest::class . '::testFive', + ], $suite->provides()); + } + + public function testNormalizeRequiredDependencies(): void + { + $suite = TestSuite::fromClassReflector(new ReflectionClass(MultiDependencyTest::class)); + + $this->assertSame([], $suite->requires()); + } + + public function testDetectMissingDependenciesBetweenTestSuites(): void + { + $suite = TestSuite::fromClassReflector( + new ReflectionClass(DependencyOnClassTest::class), + ); + + $this->assertEquals([ + DependencyOnClassTest::class . '::class', + DependencyOnClassTest::class . '::testThatDependsOnASuccessfulClass', + DependencyOnClassTest::class . '::testThatDependsOnAFailingClass', + ], $suite->provides(), 'Provided test names incorrect'); + + $this->assertEquals([ + DependencySuccessTest::class . '::class', + DependencyFailureTest::class . '::class', + ], $suite->requires(), 'Required test names incorrect'); + } + + public function testResolveDependenciesBetweenTestSuites(): void + { + $suite = TestSuite::fromClassReflector(new ReflectionClass(DependencyOnClassTest::class)); + $suite->addTestSuite(new ReflectionClass(DependencyFailureTest::class)); + $suite->addTestSuite(new ReflectionClass(DependencySuccessTest::class)); + + $this->assertEquals([ + DependencyOnClassTest::class . '::class', + DependencyOnClassTest::class . '::testThatDependsOnASuccessfulClass', + DependencyOnClassTest::class . '::testThatDependsOnAFailingClass', + DependencyFailureTest::class . '::class', + DependencyFailureTest::class . '::testOne', + DependencyFailureTest::class . '::testTwo', + DependencyFailureTest::class . '::testThree', + DependencyFailureTest::class . '::testFour', + DependencyFailureTest::class . '::testHandlesDependencyOnTestMethodThatDoesNotExist', + DependencyFailureTest::class . '::testHandlesDependencyOnTestMethodWithEmptyName', + DependencySuccessTest::class . '::class', + DependencySuccessTest::class . '::testOne', + DependencySuccessTest::class . '::testTwo', + DependencySuccessTest::class . '::testThree', + ], $suite->provides(), 'Provided test names incorrect'); + + $this->assertEquals([ + DependencyFailureTest::class . '::doesNotExist', + ], $suite->requires(), 'Required test names incorrect'); + } + + public function testResolverOnlyUsesSuitesAndCases(): void + { + $suite = TestSuite::empty('SomeName'); + $suite->addTestSuite(new ReflectionClass(DependencyOnClassTest::class)); + + $this->assertEquals([ + 'SomeName::class', + DependencyOnClassTest::class . '::class', + DependencyOnClassTest::class . '::testThatDependsOnASuccessfulClass', + DependencyOnClassTest::class . '::testThatDependsOnAFailingClass', + ], $suite->provides(), 'Provided test names incorrect'); + + $this->assertEquals([ + DependencySuccessTest::class . '::class', + DependencyFailureTest::class . '::class', + ], $suite->requires(), 'Required test names incorrect'); + } + + public function testRejectsAbstractTestClass(): void + { + $suite = TestSuite::empty('the-test-suite'); + + $this->expectException(Exception::class); + + $suite->addTestSuite(new ReflectionClass(AbstractTestCase::class)); + } + + public function testRejectsClassThatDoesNotExtendTestClass(): void + { + $suite = TestSuite::empty('the-test-suite'); + + $this->expectException(Exception::class); + + $suite->addTestSuite(new ReflectionClass(NoTestCase::class)); + } +} diff --git a/tests/unit/Logging/TestDox/NamePrettifierTest.php b/tests/unit/Logging/TestDox/NamePrettifierTest.php new file mode 100644 index 00000000000..fdf763cb31f --- /dev/null +++ b/tests/unit/Logging/TestDox/NamePrettifierTest.php @@ -0,0 +1,224 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Logging\TestDox; + +use DateTimeImmutable; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\BackedEnumeration; +use PHPUnit\TestFixture\Enumeration; +use PHPUnit\TestFixture\TestDox\TestDoxAttributeOnTestClassTest; +use PHPUnit\TestFixture\TestDoxTest; +use stdClass; + +#[CoversClass(NamePrettifier::class)] +#[Group('testdox')] +#[Small] +final class NamePrettifierTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function classNameProvider(): array + { + return [ + [ + 'Foo', + 'FooTest', + ], + [ + 'Foo', + 'TestFoo', + ], + [ + 'Foo', + 'TestsFoo', + ], + [ + 'Foo', + 'TestFooTest', + ], + [ + 'Foo (Test\Foo)', + 'Test\FooTest', + ], + [ + 'Foo (Tests\Foo)', + 'Tests\FooTest', + ], + [ + 'Unnamed Tests', + 'TestTest', + ], + [ + 'Système Testé', + 'SystèmeTestéTest', + ], + [ + 'Expression Évaluée', + 'ExpressionÉvaluéeTest', + ], + [ + 'Custom Title', + TestDoxAttributeOnTestClassTest::class, + ], + ]; + } + + /** + * @return non-empty-list + */ + public static function methodNameProvider(): array + { + return [ + [ + '', + '', + ], + [ + '', + 'test', + ], + [ + 'This is a test', + 'this_is_a_test', + ], + [ + 'This is a test', + 'test_this_is_a_test', + ], + [ + 'Foo for bar is 0', + 'testFooForBarIs0', + ], + [ + 'Foo for baz is 1', + 'testFooForBazIs1', + ], + [ + 'This has a 123 in its name', + 'testThisHasA123InItsName', + ], + [ + 'Sets redirect header on 301', + 'testSetsRedirectHeaderOn301', + ], + [ + 'Sets redirect header on 302', + 'testSetsRedirectHeaderOn302', + ], + [ + '100 users', + 'test100Users', + ], + ]; + } + + /** + * @return non-empty-list + */ + public static function objectProvider(): array + { + $object = new class + { + public function __toString(): string + { + return 'object as string'; + } + }; + + $data = [['string'], true, 0.0, 1, 'string', $object, new stdClass, Enumeration::Test, BackedEnumeration::Test, null, '']; + + $testWithDataWithIntegerKey = new TestDoxTest('testTwo'); + $testWithDataWithIntegerKey->setData(0, $data); + + $testWithDataWithStringKey = new TestDoxTest('testTwo'); + $testWithDataWithStringKey->setData('a', $data); + + $testWithDataAndTestDoxPlaceholders = new TestDoxTest('testFour'); + $testWithDataAndTestDoxPlaceholders->setData('a', $data); + + $testWithTestDoxFormatter = new TestDoxTest('testFive'); + $testWithTestDoxFormatter->setData(0, [new DateTimeImmutable('2025-07-09')]); + + return [ + [ + 'One', + new TestDoxTest('testOne'), + false, + ], + [ + 'Two with data set #0', + $testWithDataWithIntegerKey, + false, + ], + [ + 'Two with data set "a"', + $testWithDataWithStringKey, + false, + ], + [ + 'This is a custom test description', + new TestDoxTest('testThree'), + false, + ], + [ + 'This is a custom test description with placeholders array true 0.0 1 string object as string stdClass Test test null \'\' default', + $testWithDataAndTestDoxPlaceholders, + false, + ], + [ + 'This is a custom description: 2025-07-09', + $testWithTestDoxFormatter, + false, + ], + ]; + } + + /** + * @param non-empty-string $expected + * @param non-empty-string $className + */ + #[DataProvider('classNameProvider')] + public function testNameOfTestClassCanBePrettified(string $expected, string $className): void + { + $this->assertSame($expected, (new NamePrettifier)->prettifyTestClassName($className)); + } + + /** + * @param non-empty-string $expected + * @param non-empty-string $methodName + */ + #[DataProvider('methodNameProvider')] + public function testNameOfTestMethodCanBePrettified(string $expected, string $methodName): void + { + $this->assertSame($expected, (new NamePrettifier)->prettifyTestMethodName($methodName)); + } + + /** + * @param non-empty-string $expected + */ + #[DataProvider('objectProvider')] + public function test_TestCase_can_be_prettified(string $expected, TestCase $testCase, bool $colorize): void + { + $this->assertSame($expected, (new NamePrettifier)->prettifyTestCase($testCase, $colorize)); + } + + public function testStripsNumericSuffixFromTestMethodNameWhenTestMethodNameWithoutThatSuffixWasPreviouslyProcessed(): void + { + $namePrettifier = new NamePrettifier; + + $this->assertSame('This is a test', $namePrettifier->prettifyTestMethodName('testThisIsATest')); + $this->assertSame('This is a test', $namePrettifier->prettifyTestMethodName('testThisIsATest2')); + } +} diff --git a/tests/unit/Metadata/Api/CodeCoverageTest.php b/tests/unit/Metadata/Api/CodeCoverageTest.php new file mode 100644 index 00000000000..b8c8125985c --- /dev/null +++ b/tests/unit/Metadata/Api/CodeCoverageTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_shift; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\CoversClassOnClassTest; +use PHPUnit\TestFixture\CoversNothingOnClassTest; +use PHPUnit\TestFixture\Metadata\Attribute\CoversTest; +use PHPUnit\TestFixture\Metadata\Attribute\UsesTest; +use PHPUnit\TestFixture\NoCoverageAttributesTest; +use SebastianBergmann\CodeCoverage\Test\Target\Class_; +use SebastianBergmann\CodeCoverage\Test\Target\ClassesThatExtendClass; +use SebastianBergmann\CodeCoverage\Test\Target\ClassesThatImplementInterface; +use SebastianBergmann\CodeCoverage\Test\Target\Function_; +use SebastianBergmann\CodeCoverage\Test\Target\Method; +use SebastianBergmann\CodeCoverage\Test\Target\Namespace_; +use SebastianBergmann\CodeCoverage\Test\Target\Trait_; + +#[CoversClass(CodeCoverage::class)] +#[Small] +#[Group('metadata')] +final class CodeCoverageTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function canSkipCoverageProvider(): array + { + return [ + [false, NoCoverageAttributesTest::class], + [false, CoversClassOnClassTest::class], + [true, CoversNothingOnClassTest::class], + ]; + } + + #[TestDox('Maps #[Covers*()] metadata to phpunit/php-code-coverage TargetCollection')] + public function testMapsCoversMetadataToCodeCoverageTargetCollection(): void + { + $targets = (new CodeCoverage)->coversTargets(CoversTest::class, 'testOne'); + + $this->assertNotFalse($targets); + $this->assertCount(7, $targets); + + $targets = $targets->asArray(); + + $target = array_shift($targets); + $this->assertInstanceOf(Namespace_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute', $target->namespace()); + + $target = array_shift($targets); + $this->assertInstanceOf(Class_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + + $target = array_shift($targets); + $this->assertInstanceOf(ClassesThatExtendClass::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + + $target = array_shift($targets); + $this->assertInstanceOf(ClassesThatImplementInterface::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->interfaceName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Trait_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait', $target->traitName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Method::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + $this->assertSame('method', $target->methodName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Function_::class, $target); + $this->assertSame('f', $target->functionName()); + } + + #[TestDox('Maps #[Uses*()] metadata to phpunit/php-code-coverage TargetCollection')] + public function testMapsUsesMetadataToCodeCoverageTargetCollection(): void + { + $targets = (new CodeCoverage)->usesTargets(UsesTest::class, 'testOne'); + + $this->assertNotFalse($targets); + $this->assertCount(7, $targets); + + $targets = $targets->asArray(); + + $target = array_shift($targets); + $this->assertInstanceOf(Namespace_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute', $target->namespace()); + + $target = array_shift($targets); + $this->assertInstanceOf(Class_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + + $target = array_shift($targets); + $this->assertInstanceOf(ClassesThatExtendClass::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + + $target = array_shift($targets); + $this->assertInstanceOf(ClassesThatImplementInterface::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->interfaceName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Trait_::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait', $target->traitName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Method::class, $target); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\Example', $target->className()); + $this->assertSame('method', $target->methodName()); + + $target = array_shift($targets); + $this->assertInstanceOf(Function_::class, $target); + $this->assertSame('f', $target->functionName()); + } + + /** + * @param class-string $testCase + */ + #[DataProvider('canSkipCoverageProvider')] + public function testWhetherCollectionOfCodeCoverageDataCanBeSkippedCanBeDetermined(bool $expected, string $testCase): void + { + $test = new $testCase('testSomething'); + $coverageRequired = (new CodeCoverage)->shouldCodeCoverageBeCollectedFor($test); + $canSkipCoverage = !$coverageRequired; + + $this->assertSame($expected, $canSkipCoverage); + } +} diff --git a/tests/unit/Metadata/Api/DataProviderTest.php b/tests/unit/Metadata/Api/DataProviderTest.php new file mode 100644 index 00000000000..28e5f1bd79b --- /dev/null +++ b/tests/unit/Metadata/Api/DataProviderTest.php @@ -0,0 +1,228 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\InvalidDataProviderException; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\DuplicateKeyDataProvidersTest; +use PHPUnit\TestFixture\DuplicateKeyDataProviderTest; +use PHPUnit\TestFixture\MultipleDataProviderTest; +use PHPUnit\TestFixture\TestWithAttributeDataProviderTest; +use PHPUnit\TestFixture\VariousIterableDataProviderTest; + +#[CoversClass(DataProvider::class)] +#[Small] +#[Group('metadata')] +final class DataProviderTest extends TestCase +{ + /** + * Check if all data providers are being merged. + */ + public function testMultipleDataProviders(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(MultipleDataProviderTest::class, 'testOne'), + ); + + $this->assertCount(9, $dataSets); + + $aCount = 0; + $bCount = 0; + $cCount = 0; + + for ($i = 0; $i < 9; $i++) { + $aCount += $dataSets[$i][0] != null ? 1 : 0; + $bCount += $dataSets[$i][1] != null ? 1 : 0; + $cCount += $dataSets[$i][2] != null ? 1 : 0; + } + + $this->assertEquals(3, $aCount); + $this->assertEquals(3, $bCount); + $this->assertEquals(3, $cCount); + } + + public function testMultipleYieldIteratorDataProviders(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(MultipleDataProviderTest::class, 'testTwo'), + ); + + $this->assertCount(9, $dataSets); + + $aCount = 0; + $bCount = 0; + $cCount = 0; + + for ($i = 0; $i < 9; $i++) { + $aCount += $dataSets[$i][0] != null ? 1 : 0; + $bCount += $dataSets[$i][1] != null ? 1 : 0; + $cCount += $dataSets[$i][2] != null ? 1 : 0; + } + + $this->assertEquals(3, $aCount); + $this->assertEquals(3, $bCount); + $this->assertEquals(3, $cCount); + } + + public function testWithVariousIterableDataProvidersFromParent(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testFromParent'), + ); + + $this->assertEquals([ + ['J'], + ['K'], + ['L'], + ['M'], + ['N'], + ['O'], + ['P'], + ['Q'], + ['R'], + ], $dataSets); + } + + public function testWithVariousIterableDataProvidersInParent(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testInParent'), + ); + + $this->assertEquals([ + ['J'], + ['K'], + ['L'], + ['M'], + ['N'], + ['O'], + ['P'], + ['Q'], + ['R'], + ], $dataSets); + } + + public function testWithVariousIterableAbstractDataProviders(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testAbstract'), + ); + + $this->assertEquals([ + ['S'], + ['T'], + ['U'], + ['V'], + ['W'], + ['X'], + ['Y'], + ['Z'], + ['P'], + ], $dataSets); + } + + public function testWithVariousIterableStaticDataProviders(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testStatic'), + ); + + $this->assertEquals([ + ['A'], + ['B'], + ['C'], + ['D'], + ['E'], + ['F'], + ['G'], + ['H'], + ['I'], + ], $dataSets); + } + + public function testWithVariousIterableNonStaticDataProviders(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(VariousIterableDataProviderTest::class, 'testNonStatic'), + ); + + $this->assertEquals([ + ['S'], + ['T'], + ['U'], + ['V'], + ['W'], + ['X'], + ['Y'], + ['Z'], + ['P'], + ], $dataSets); + } + + public function testWithDuplicateKeyDataProvider(): void + { + $this->expectException(InvalidDataProviderException::class); + $this->expectExceptionMessage('The key "foo" has already been defined by provider PHPUnit\TestFixture\DuplicateKeyDataProviderTest::dataProvider'); + + /* @noinspection UnusedFunctionResultInspection */ + (new DataProvider)->providedData(DuplicateKeyDataProviderTest::class, 'test'); + } + + public function testTestWithAttribute(): void + { + $dataSets = $this->getRawDataFromProvidedData( + (new DataProvider)->providedData(TestWithAttributeDataProviderTest::class, 'testWithAttribute'), + ); + + $this->assertSame([ + 'foo' => ['a', 'b'], + 'bar' => ['c', 'd'], + 0 => ['e', 'f'], + 1 => ['g', 'h'], + ], $dataSets); + } + + public function testTestWithAttributeWithDuplicateKey(): void + { + $this->expectException(InvalidDataProviderException::class); + $this->expectExceptionMessage('The key "foo" has already been defined by TestWith#0 attribute'); + + /* @noinspection UnusedFunctionResultInspection */ + (new DataProvider)->providedData(TestWithAttributeDataProviderTest::class, 'testWithDuplicateName'); + } + + public function testWithDuplicateKeyDataProviders(): void + { + $this->expectException(InvalidDataProviderException::class); + $this->expectExceptionMessage('The key "bar" has already been defined by provider PHPUnit\TestFixture\DuplicateKeyDataProvidersTest::dataProvider1'); + + /* @noinspection UnusedFunctionResultInspection */ + (new DataProvider)->providedData(DuplicateKeyDataProvidersTest::class, 'test'); + } + + /** + * @param array $providedData + * + * @return array + */ + private function getRawDataFromProvidedData(array $providedData): array + { + $raw = []; + + foreach ($providedData as $key => $data) { + $raw[$key] = $data->value(); + } + + return $raw; + } +} diff --git a/tests/unit/Metadata/Api/GroupsTest.php b/tests/unit/Metadata/Api/GroupsTest.php new file mode 100644 index 00000000000..08ff574e84c --- /dev/null +++ b/tests/unit/Metadata/Api/GroupsTest.php @@ -0,0 +1,131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\LargeGroupAttributesTest; +use PHPUnit\TestFixture\MediumGroupAttributesTest; +use PHPUnit\TestFixture\NoGroupsMetadataTest; +use PHPUnit\TestFixture\SmallGroupAnnotationsTest; +use PHPUnit\TestFixture\SmallGroupAttributesTest; + +#[CoversClass(Groups::class)] +#[Small] +#[Group('metadata')] +final class GroupsTest extends TestCase +{ + public static function provider(): array + { + return [ + [ + [ + ], + NoGroupsMetadataTest::class, + 'testOne', + false, + ], + + [ + [ + 'the-group', + 'the-ticket', + 'small', + 'another-group', + 'another-ticket', + ], + SmallGroupAttributesTest::class, + 'testOne', + false, + ], + + [ + [ + 'the-group', + 'the-ticket', + 'small', + 'another-group', + 'another-ticket', + ], + SmallGroupAnnotationsTest::class, + 'testOne', + false, + ], + + [ + [ + 'the-group', + 'the-ticket', + 'small', + 'another-group', + 'another-ticket', + '__phpunit_covers_phpunit\testfixture\coveredclass', + '__phpunit_uses_phpunit\testfixture\coveredclass', + ], + SmallGroupAttributesTest::class, + 'testOne', + true, + ], + + [ + [ + 'the-group', + 'the-ticket', + 'small', + 'another-group', + 'another-ticket', + '__phpunit_covers_phpunit\testfixture\coveredclass', + '__phpunit_uses_phpunit\testfixture\coveredclass', + ], + SmallGroupAnnotationsTest::class, + 'testOne', + true, + ], + + [ + [ + 'medium', + ], + MediumGroupAttributesTest::class, + 'testOne', + false, + ], + + [ + [ + 'large', + ], + LargeGroupAttributesTest::class, + 'testOne', + false, + ], + ]; + } + + #[DataProvider('provider')] + public function testAssignsGroups(array $expected, string $className, string $methodName, bool $includeVirtual): void + { + $this->assertSame( + $expected, + (new Groups)->groups($className, $methodName, $includeVirtual), + ); + } + + public function testAssignsSize(): void + { + $this->assertTrue((new Groups)->size(SmallGroupAttributesTest::class, 'testOne')->isSmall()); + $this->assertTrue((new Groups)->size(MediumGroupAttributesTest::class, 'testOne')->isMedium()); + $this->assertTrue((new Groups)->size(LargeGroupAttributesTest::class, 'testOne')->isLarge()); + $this->assertTrue((new Groups)->size(NoGroupsMetadataTest::class, 'testOne')->isUnknown()); + } +} diff --git a/tests/unit/Metadata/Api/HookMethodsTest.php b/tests/unit/Metadata/Api/HookMethodsTest.php new file mode 100644 index 00000000000..f912b50205a --- /dev/null +++ b/tests/unit/Metadata/Api/HookMethodsTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use function array_keys; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\HookMethod; +use PHPUnit\Runner\HookMethodCollection; +use PHPUnit\TestFixture\TestWithHookMethodsPrioritizedTest; +use PHPUnit\TestFixture\TestWithHookMethodsTest; +use PHPUnit\TestFixture\TestWithoutHookMethodsTest; + +#[CoversClass(HookMethods::class)] +#[Small] +#[Group('metadata')] +final class HookMethodsTest extends TestCase +{ + public function testReturnsDefaultHookMethodsForClassThatDoesNotExist(): void + { + $this->assertEquals( + [ + 'beforeClass' => HookMethodCollection::defaultBeforeClass(), + 'before' => HookMethodCollection::defaultBefore(), + 'preCondition' => HookMethodCollection::defaultPreCondition(), + 'postCondition' => HookMethodCollection::defaultPostCondition(), + 'after' => HookMethodCollection::defaultAfter(), + 'afterClass' => HookMethodCollection::defaultAfterClass(), + ], + (new HookMethods)->hookMethods('does not exist'), + ); + } + + public function testReturnsDefaultHookMethodsInTestClassWithoutHookMethods(): void + { + $this->assertEquals( + [ + 'beforeClass' => HookMethodCollection::defaultBeforeClass(), + 'before' => HookMethodCollection::defaultBefore(), + 'preCondition' => HookMethodCollection::defaultPreCondition(), + 'postCondition' => HookMethodCollection::defaultPostCondition(), + 'after' => HookMethodCollection::defaultAfter(), + 'afterClass' => HookMethodCollection::defaultAfterClass(), + ], + (new HookMethods)->hookMethods(TestWithoutHookMethodsTest::class), + ); + } + + public function testFindsHookMethodsInTestClassWithHookMethods(): void + { + $hookMethods = (new HookMethods)->hookMethods(TestWithHookMethodsTest::class); + $this->assertSame(['beforeClass', 'before', 'preCondition', 'postCondition', 'after', 'afterClass'], array_keys($hookMethods)); + + $beforeClassHooks = HookMethodCollection::defaultBeforeClass(); + $beforeClassHooks->add(new HookMethod('beforeFirstTestWithAttribute', 0)); + $this->assertEquals($beforeClassHooks, $hookMethods['beforeClass']); + + $beforeHooks = HookMethodCollection::defaultBefore(); + $beforeHooks->add(new HookMethod('beforeEachTestWithAttribute', 0)); + $this->assertEquals($beforeHooks, $hookMethods['before']); + + $preConditionHooks = HookMethodCollection::defaultPreCondition(); + $preConditionHooks->add(new HookMethod('preConditionsWithAttribute', 0)); + $this->assertEquals($preConditionHooks, $hookMethods['preCondition']); + + $postConditionHooks = HookMethodCollection::defaultPostCondition(); + $postConditionHooks->add(new HookMethod('postConditionsWithAttribute', 0)); + $this->assertEquals($postConditionHooks, $hookMethods['postCondition']); + + $afterHooks = HookMethodCollection::defaultAfter(); + $afterHooks->add(new HookMethod('afterEachTestWithAttribute', 0)); + $this->assertEquals($afterHooks, $hookMethods['after']); + + $afterClassHooks = HookMethodCollection::defaultAfterClass(); + $afterClassHooks->add(new HookMethod('afterLastTestWithAttribute', 0)); + $this->assertEquals($afterClassHooks, $hookMethods['afterClass']); + } + + public function testFindsHookMethodsInTestClassWithHookMethodsPrioritized(): void + { + $hookMethods = (new HookMethods)->hookMethods(TestWithHookMethodsPrioritizedTest::class); + $this->assertSame(['beforeClass', 'before', 'preCondition', 'postCondition', 'after', 'afterClass'], array_keys($hookMethods)); + + $beforeClassHooks = HookMethodCollection::defaultBeforeClass(); + $beforeClassHooks->add(new HookMethod('beforeFirstTest', 1)); + $this->assertEquals($beforeClassHooks, $hookMethods['beforeClass']); + + $beforeHooks = HookMethodCollection::defaultBefore(); + $beforeHooks->add(new HookMethod('beforeEachTest', 2)); + $this->assertEquals($beforeHooks, $hookMethods['before']); + + $preConditionHooks = HookMethodCollection::defaultPreCondition(); + $preConditionHooks->add(new HookMethod('preConditions', 3)); + $this->assertEquals($preConditionHooks, $hookMethods['preCondition']); + + $postConditionHooks = HookMethodCollection::defaultPostCondition(); + $postConditionHooks->add(new HookMethod('postConditions', 4)); + $this->assertEquals($postConditionHooks, $hookMethods['postCondition']); + + $afterHooks = HookMethodCollection::defaultAfter(); + $afterHooks->add(new HookMethod('afterEachTest', 5)); + $this->assertEquals($afterHooks, $hookMethods['after']); + + $afterClassHooks = HookMethodCollection::defaultAfterClass(); + $afterClassHooks->add(new HookMethod('afterLastTest', 6)); + $this->assertEquals($afterClassHooks, $hookMethods['afterClass']); + } +} diff --git a/tests/unit/Metadata/Api/RequirementsTest.php b/tests/unit/Metadata/Api/RequirementsTest.php new file mode 100644 index 00000000000..0bd0be255bc --- /dev/null +++ b/tests/unit/Metadata/Api/RequirementsTest.php @@ -0,0 +1,162 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Api; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\RequirementsEnvironmentVariableTest; + +#[CoversClass(Requirements::class)] +#[Small] +#[Group('metadata')] +final class RequirementsTest extends TestCase +{ + public static function missingRequirementsProvider(): array + { + return [ + ['testOne', []], + ['testNine', [ + 'Function testFunc() is required.', + ]], + ['testTen', [ + 'PHP extension testExt is required.', + ]], + ['testAlwaysSkip', [ + 'PHPUnit >= 1111111 is required.', + ]], + ['testAlwaysSkip2', [ + 'PHP >= 9999999 is required.', + ]], + ['testAlwaysSkip3', [ + 'Operating system DOESNOTEXIST is required.', + ]], + ['testAllPossibleRequirements', [ + 'PHP 99-dev is required.', + 'PHPUnit 99-dev is required.', + 'Operating system DOESNOTEXIST is required.', + 'Operating system DOESNOTEXIST is required.', + 'Function testFuncOne() is required.', + 'Function testFunc2() is required.', + 'Method DoesNotExist::doesNotExist() is required.', + 'PHP extension testExtOne is required.', + 'PHP extension testExt2 is required.', + 'PHP extension testExtThree >= 2.0 is required.', + 'Setting "not_a_setting" is required to be "Off".', + ]], + ['testPHPVersionOperatorLessThan', [ + 'PHP < 5.4 is required.', + ]], + ['testPHPVersionOperatorLessThanEquals', [ + 'PHP <= 5.4 is required.', + ]], + ['testPHPVersionOperatorGreaterThan', [ + 'PHP > 99 is required.', + ]], + ['testPHPVersionOperatorGreaterThanEquals', [ + 'PHP >= 99 is required.', + ]], + ['testPHPVersionOperatorNoSpace', [ + 'PHP >= 99 is required.', + ]], + ['testPHPVersionOperatorEquals', [ + 'PHP = 5.4 is required.', + ]], + ['testPHPVersionOperatorDoubleEquals', [ + 'PHP == 5.4 is required.', + ]], + ['testPHPUnitVersionOperatorLessThan', [ + 'PHPUnit < 1.0 is required.', + ]], + ['testPHPUnitVersionOperatorLessThanEquals', [ + 'PHPUnit <= 1.0 is required.', + ]], + ['testPHPUnitVersionOperatorGreaterThan', [ + 'PHPUnit > 99 is required.', + ]], + ['testPHPUnitVersionOperatorGreaterThanEquals', [ + 'PHPUnit >= 99 is required.', + ]], + ['testPHPUnitVersionOperatorEquals', [ + 'PHPUnit = 1.0 is required.', + ]], + ['testPHPUnitVersionOperatorDoubleEquals', [ + 'PHPUnit == 1.0 is required.', + ]], + ['testPHPUnitVersionOperatorNoSpace', [ + 'PHPUnit >= 99 is required.', + ]], + ['testExtensionVersionOperatorLessThan', [ + 'PHP extension testExtOne < 1.0 is required.', + ]], + ['testExtensionVersionOperatorLessThanEquals', [ + 'PHP extension testExtOne <= 1.0 is required.', + ]], + ['testExtensionVersionOperatorGreaterThan', [ + 'PHP extension testExtOne > 99 is required.', + ]], + ['testExtensionVersionOperatorGreaterThanEquals', [ + 'PHP extension testExtOne >= 99 is required.', + ]], + ['testExtensionVersionOperatorEquals', [ + 'PHP extension testExtOne = 1.0 is required.', + ]], + ['testExtensionVersionOperatorDoubleEquals', [ + 'PHP extension testExtOne == 1.0 is required.', + ]], + ['testExtensionVersionOperatorNoSpace', [ + 'PHP extension testExtOne >= 99 is required.', + ]], + ['testVersionConstraintTildeMajor', [ + 'PHP ~1.0 is required.', + 'PHPUnit ~2.0 is required.', + ]], + ['testVersionConstraintCaretMajor', [ + 'PHP ^1.0 is required.', + 'PHPUnit ^2.0 is required.', + ]], + ['testPHPUnitExtensionRequired', [ + 'PHPUnit extension "PHPUnit\TestFixture\SomeExtension" is required.', + 'PHPUnit extension "PHPUnit\TestFixture\SomeOtherExtension" is required.', + ]], + ]; + } + + protected function tearDown(): void + { + unset($_ENV['FOO'], $_ENV['BAR']); + } + + #[DataProvider('missingRequirementsProvider')] + public function testGetMissingRequirements(string $test, array $result): void + { + $this->assertEquals( + $result, + (new Requirements)->requirementsNotSatisfiedFor(\PHPUnit\TestFixture\RequirementsTest::class, $test), + ); + } + + public function testGetMissingEnvironmentVariableRequirements(): void + { + $_ENV['FOO'] = 'foo'; + $_ENV['BAR'] = ''; + + $this->assertEquals( + [ + 'Environment variable "FOO" is required to be "bar".', + 'Environment variable "BAR" is required.', + 'Environment variable "BAZ" is required.', + ], + (new Requirements)->requirementsNotSatisfiedFor(RequirementsEnvironmentVariableTest::class, 'testRequiresEnvironmentVariable'), + ); + } +} diff --git a/tests/unit/Metadata/MetadataCollectionTest.php b/tests/unit/Metadata/MetadataCollectionTest.php new file mode 100644 index 00000000000..b2506cae0dc --- /dev/null +++ b/tests/unit/Metadata/MetadataCollectionTest.php @@ -0,0 +1,644 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Util\VersionComparisonOperator; +use stdClass; + +#[CoversClass(MetadataCollection::class)] +#[CoversClass(MetadataCollectionIterator::class)] +#[UsesClass(After::class)] +#[UsesClass(AfterClass::class)] +#[UsesClass(BackupGlobals::class)] +#[UsesClass(BackupStaticProperties::class)] +#[UsesClass(Before::class)] +#[UsesClass(BeforeClass::class)] +#[UsesClass(CoversClass::class)] +#[UsesClass(CoversFunction::class)] +#[UsesClass(CoversMethod::class)] +#[UsesClass(CoversNothing::class)] +#[UsesClass(DataProvider::class)] +#[UsesClass(DependsOnClass::class)] +#[UsesClass(DependsOnMethod::class)] +#[UsesClass(DisableReturnValueGenerationForTestDoubles::class)] +#[UsesClass(DoesNotPerformAssertions::class)] +#[UsesClass(Group::class)] +#[UsesClass(Metadata::class)] +#[UsesClass(PostCondition::class)] +#[UsesClass(PreCondition::class)] +#[UsesClass(PreserveGlobalState::class)] +#[UsesClass(RequiresFunction::class)] +#[UsesClass(RequiresMethod::class)] +#[UsesClass(RequiresOperatingSystem::class)] +#[UsesClass(RequiresOperatingSystemFamily::class)] +#[UsesClass(RequiresPhp::class)] +#[UsesClass(RequiresPhpExtension::class)] +#[UsesClass(RequiresPhpunit::class)] +#[UsesClass(RequiresPhpunitExtension::class)] +#[UsesClass(RequiresEnvironmentVariable::class)] +#[UsesClass(RequiresSetting::class)] +#[UsesClass(RunInSeparateProcess::class)] +#[UsesClass(RunTestsInSeparateProcesses::class)] +#[UsesClass(Test::class)] +#[UsesClass(TestDox::class)] +#[UsesClass(TestWith::class)] +#[UsesClass(UsesClass::class)] +#[UsesClass(UsesFunction::class)] +#[Small] +#[Group('metadata')] +final class MetadataCollectionTest extends TestCase +{ + public function testCanBeEmpty(): void + { + $collection = MetadataCollection::fromArray([]); + + $this->assertCount(0, $collection); + $this->assertTrue($collection->isEmpty()); + $this->assertFalse($collection->isNotEmpty()); + } + + public function testCanBeCreatedFromArray(): void + { + $metadata = Metadata::test(); + + $collection = MetadataCollection::fromArray([$metadata]); + + $this->assertContains($metadata, $collection); + } + + public function testIsCountable(): void + { + $metadata = Metadata::test(); + + $collection = MetadataCollection::fromArray([$metadata]); + + $this->assertCount(1, $collection); + $this->assertFalse($collection->isEmpty()); + $this->assertTrue($collection->isNotEmpty()); + } + + public function testIsIterable(): void + { + $metadata = Metadata::test(); + + foreach (MetadataCollection::fromArray([$metadata]) as $key => $value) { + $this->assertSame(0, $key); + $this->assertSame($metadata, $value); + } + } + + public function testCanBeMerged(): void + { + $a = MetadataCollection::fromArray([Metadata::before(0)]); + $b = MetadataCollection::fromArray([Metadata::after(0)]); + $c = $a->mergeWith($b); + + $this->assertCount(2, $c); + $this->assertTrue($c->asArray()[0]->isBefore()); + $this->assertTrue($c->asArray()[1]->isAfter()); + } + + public function test_Can_be_filtered_for_class_level_metadata(): void + { + $collection = MetadataCollection::fromArray( + [ + Metadata::coversClass(''), + Metadata::ignoreDeprecationsOnMethod(), + ], + ); + + $this->assertCount(2, $collection); + + $this->assertCount(1, $collection->isClassLevel()); + $this->assertTrue($collection->isClassLevel()->asArray()[0]->isClassLevel()); + + $this->assertCount(1, $collection->isMethodLevel()); + $this->assertTrue($collection->isMethodLevel()->asArray()[0]->isMethodLevel()); + } + + public function test_Can_be_filtered_for_AfterClass(): void + { + $collection = $this->collectionWithOneOfEach()->isAfterClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isAfterClass()); + } + + public function test_Can_be_filtered_for_After(): void + { + $collection = $this->collectionWithOneOfEach()->isAfter(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isAfter()); + } + + public function test_Can_be_filtered_for_AllowMockObjectsWithoutExpectations(): void + { + $collection = $this->collectionWithOneOfEach()->isAllowMockObjectsWithoutExpectations(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isAllowMockObjectsWithoutExpectations()); + } + + public function test_Can_be_filtered_for_BackupGlobals(): void + { + $collection = $this->collectionWithOneOfEach()->isBackupGlobals(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isBackupGlobals()); + } + + public function test_Can_be_filtered_for_BackupStaticProperties(): void + { + $collection = $this->collectionWithOneOfEach()->isBackupStaticProperties(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isBackupStaticProperties()); + } + + public function test_Can_be_filtered_for_BeforeClass(): void + { + $collection = $this->collectionWithOneOfEach()->isBeforeClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isBeforeClass()); + } + + public function test_Can_be_filtered_for_Before(): void + { + $collection = $this->collectionWithOneOfEach()->isBefore(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isBefore()); + } + + public function test_Can_be_filtered_for_CoversNamespace(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversNamespace(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversNamespace()); + } + + public function test_Can_be_filtered_for_CoversClass(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversClass()); + } + + public function test_Can_be_filtered_for_CoversClassesThatExtendClass(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversClassesThatExtendClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversClassesThatExtendClass()); + } + + public function test_Can_be_filtered_for_CoversClassesThatImplementInterface(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversClassesThatImplementInterface(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversClassesThatImplementInterface()); + } + + public function test_Can_be_filtered_for_CoversTrait(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversTrait(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversTrait()); + } + + public function test_Can_be_filtered_for_CoversFunction(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversFunction(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversFunction()); + } + + public function test_Can_be_filtered_for_CoversMethod(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversMethod(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversMethod()); + } + + public function test_Can_be_filtered_for_CoversNothing(): void + { + $collection = $this->collectionWithOneOfEach()->isCoversNothing(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isCoversNothing()); + } + + public function test_Can_be_filtered_for_DataProvider(): void + { + $collection = $this->collectionWithOneOfEach()->isDataProvider(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isDataProvider()); + } + + public function test_Can_be_filtered_for_Depends(): void + { + $collection = $this->collectionWithOneOfEach()->isDepends(); + + $this->assertCount(2, $collection); + $this->assertTrue($collection->asArray()[0]->isDependsOnClass()); + $this->assertTrue($collection->asArray()[1]->isDependsOnMethod()); + } + + public function test_Can_be_filtered_for_DependsOnClass(): void + { + $collection = $this->collectionWithOneOfEach()->isDependsOnClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isDependsOnClass()); + } + + public function test_Can_be_filtered_for_DependsOnMethod(): void + { + $collection = $this->collectionWithOneOfEach()->isDependsOnMethod(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isDependsOnMethod()); + } + + public function test_Can_be_filtered_for_DisableReturnValueGenerationForTestDoubles(): void + { + $collection = $this->collectionWithOneOfEach()->isDisableReturnValueGenerationForTestDoubles(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isDisableReturnValueGenerationForTestDoubles()); + } + + public function test_Can_be_filtered_for_DoesNotPerformAssertions(): void + { + $collection = $this->collectionWithOneOfEach()->isDoesNotPerformAssertions(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isDoesNotPerformAssertions()); + } + + public function test_Can_be_filtered_for_ExcludeGlobalVariableFromBackup(): void + { + $collection = $this->collectionWithOneOfEach()->isExcludeGlobalVariableFromBackup(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isExcludeGlobalVariableFromBackup()); + } + + public function test_Can_be_filtered_for_ExcludeStaticPropertyFromBackup(): void + { + $collection = $this->collectionWithOneOfEach()->isExcludeStaticPropertyFromBackup(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isExcludeStaticPropertyFromBackup()); + } + + public function test_Can_be_filtered_for_Group(): void + { + $collection = $this->collectionWithOneOfEach()->isGroup(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isGroup()); + } + + public function test_Can_be_filtered_for_IgnoreDeprecations(): void + { + $collection = $this->collectionWithOneOfEach()->isIgnoreDeprecations(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isIgnoreDeprecations()); + } + + public function test_Can_be_filtered_for_IgnorePhpunitDeprecations(): void + { + $collection = $this->collectionWithOneOfEach()->isIgnorePhpunitDeprecations(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isIgnorePhpunitDeprecations()); + } + + public function test_Can_be_filtered_for_IgnorePhpunitWarnings(): void + { + $collection = $this->collectionWithOneOfEach()->isIgnorePhpunitWarnings(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isIgnorePhpunitWarnings()); + } + + public function test_Can_be_filtered_for_PostCondition(): void + { + $collection = $this->collectionWithOneOfEach()->isPostCondition(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isPostCondition()); + } + + public function test_Can_be_filtered_for_PreCondition(): void + { + $collection = $this->collectionWithOneOfEach()->isPreCondition(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isPreCondition()); + } + + public function test_Can_be_filtered_for_PreserveGlobalState(): void + { + $collection = $this->collectionWithOneOfEach()->isPreserveGlobalState(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isPreserveGlobalState()); + } + + public function test_Can_be_filtered_for_RequiresMethod(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresMethod(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresMethod()); + } + + public function test_Can_be_filtered_for_RequiresFunction(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresFunction(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresFunction()); + } + + public function test_Can_be_filtered_for_RequiresOperatingSystemFamily(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresOperatingSystemFamily(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresOperatingSystemFamily()); + } + + public function test_Can_be_filtered_for_RequiresOperatingSystem(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresOperatingSystem(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresOperatingSystem()); + } + + public function test_Can_be_filtered_for_RequiresPhpExtension(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresPhpExtension(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresPhpExtension()); + } + + public function test_Can_be_filtered_for_RequiresPhp(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresPhp(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresPhp()); + } + + public function test_Can_be_filtered_for_RequiresPhpunit(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresPhpunit(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresPhpunit()); + } + + public function test_Can_be_filtered_for_RequiresPhpunitExtension(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresPhpunitExtension(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresPhpunitExtension()); + } + + public function test_Can_be_filtered_for_RequiresEnvironmentVariable(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresEnvironmentVariable(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresEnvironmentVariable()); + } + + public function test_Can_be_filtered_for_WithEnvironmentVariable(): void + { + $collection = $this->collectionWithOneOfEach()->isWithEnvironmentVariable(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isWithEnvironmentVariable()); + } + + public function test_Can_be_filtered_for_RequiresSetting(): void + { + $collection = $this->collectionWithOneOfEach()->isRequiresSetting(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRequiresSetting()); + } + + public function test_Can_be_filtered_for_RunInSeparateProcess(): void + { + $collection = $this->collectionWithOneOfEach()->isRunInSeparateProcess(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRunInSeparateProcess()); + } + + public function test_Can_be_filtered_for_RunTestsInSeparateProcesses(): void + { + $collection = $this->collectionWithOneOfEach()->isRunTestsInSeparateProcesses(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isRunTestsInSeparateProcesses()); + } + + public function test_Can_be_filtered_for_TestDox(): void + { + $collection = $this->collectionWithOneOfEach()->isTestDox(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isTestDox()); + } + + public function test_Can_be_filtered_for_TestDoxFormatter(): void + { + $collection = $this->collectionWithOneOfEach()->isTestDoxFormatter(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isTestDoxFormatter()); + } + + public function test_Can_be_filtered_for_Test(): void + { + $collection = $this->collectionWithOneOfEach()->isTest(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isTest()); + } + + public function test_Can_be_filtered_for_TestWith(): void + { + $collection = $this->collectionWithOneOfEach()->isTestWith(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isTestWith()); + } + + public function test_Can_be_filtered_for_UsesNamespace(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesNamespace(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesNamespace()); + } + + public function test_Can_be_filtered_for_UsesClass(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesClass()); + } + + public function test_Can_be_filtered_for_UsesClassesThatExtendClass(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesClassesThatExtendClass(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesClassesThatExtendClass()); + } + + public function test_Can_be_filtered_for_UsesClassesThatImplementInterface(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesClassesThatImplementInterface(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesClassesThatImplementInterface()); + } + + public function test_Can_be_filtered_for_UsesTrait(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesTrait(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesTrait()); + } + + public function test_Can_be_filtered_for_UsesFunction(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesFunction(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesFunction()); + } + + public function test_Can_be_filtered_for_UsesMethod(): void + { + $collection = $this->collectionWithOneOfEach()->isUsesMethod(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isUsesMethod()); + } + + public function test_Can_be_filtered_for_WithoutErrorHandler(): void + { + $collection = $this->collectionWithOneOfEach()->isWithoutErrorHandler(); + + $this->assertCount(1, $collection); + $this->assertTrue($collection->asArray()[0]->isWithoutErrorHandler()); + } + + private function collectionWithOneOfEach(): MetadataCollection + { + return MetadataCollection::fromArray( + [ + Metadata::afterClass(0), + Metadata::after(0), + Metadata::allowMockObjectsWithoutExpectationsOnClass(), + Metadata::backupGlobalsOnClass(true), + Metadata::backupStaticPropertiesOnClass(true), + Metadata::beforeClass(0), + Metadata::before(0), + Metadata::coversNamespace(''), + Metadata::coversClass(''), + Metadata::coversClassesThatExtendClass(''), + Metadata::coversClassesThatImplementInterface(''), + Metadata::coversTrait(''), + Metadata::coversFunction(''), + Metadata::coversMethod('', ''), + Metadata::coversNothingOnClass(), + Metadata::dataProvider('', '', true), + Metadata::dependsOnClass('', false, false), + Metadata::dependsOnMethod('', '', false, false), + Metadata::disableReturnValueGenerationForTestDoubles(), + Metadata::doesNotPerformAssertionsOnClass(), + Metadata::excludeGlobalVariableFromBackupOnClass(''), + Metadata::excludeStaticPropertyFromBackupOnClass('', ''), + Metadata::groupOnClass(''), + Metadata::ignoreDeprecationsOnClass(), + Metadata::ignorePhpunitDeprecationsOnClass(), + Metadata::ignorePhpunitWarnings(null), + Metadata::postCondition(0), + Metadata::preCondition(0), + Metadata::preserveGlobalStateOnClass(true), + Metadata::requiresMethodOnClass('', ''), + Metadata::requiresFunctionOnClass(''), + Metadata::requiresOperatingSystemFamilyOnClass(''), + Metadata::requiresOperatingSystemOnClass(''), + Metadata::requiresPhpExtensionOnClass('', null), + Metadata::requiresPhpOnClass( + new ComparisonRequirement( + '8.0.0', + new VersionComparisonOperator('>='), + ), + ), + Metadata::requiresPhpunitOnClass( + new ComparisonRequirement( + '10.0.0', + new VersionComparisonOperator('>='), + ), + ), + Metadata::requiresPhpunitExtensionOnClass(stdClass::class), + Metadata::requiresEnvironmentVariableOnClass('foo', 'bar'), + Metadata::requiresSettingOnClass('foo', 'bar'), + Metadata::runInSeparateProcess(), + Metadata::runTestsInSeparateProcesses(), + Metadata::testDoxOnClass(''), + Metadata::testDoxFormatter('', ''), + Metadata::test(), + Metadata::testWith([]), + Metadata::usesNamespace(''), + Metadata::usesClass(''), + Metadata::usesClassesThatExtendClass(''), + Metadata::usesClassesThatImplementInterface(''), + Metadata::usesTrait(''), + Metadata::usesFunction(''), + Metadata::usesMethod('', ''), + Metadata::withEnvironmentVariableOnClass('foo', 'bar'), + Metadata::withoutErrorHandler(), + ], + ); + } +} diff --git a/tests/unit/Metadata/MetadataTest.php b/tests/unit/Metadata/MetadataTest.php new file mode 100644 index 00000000000..3ce1be738b4 --- /dev/null +++ b/tests/unit/Metadata/MetadataTest.php @@ -0,0 +1,5131 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(Metadata::class)] +#[CoversClassesThatExtendClass(Metadata::class)] +#[Small] +#[Group('metadata')] +final class MetadataTest extends TestCase +{ + public function testCanBeAfter(): void + { + $priority = 0; + + $metadata = Metadata::after($priority); + + $this->assertTrue($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBeAfterClass(): void + { + $priority = 0; + + $metadata = Metadata::afterClass($priority); + + $this->assertFalse($metadata->isAfter()); + $this->assertTrue($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBeAllowMockObjectsWithoutExpectations(): void + { + $metadata = Metadata::allowMockObjectsWithoutExpectationsOnClass(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertTrue($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeBackupGlobalsOnClass(): void + { + $metadata = Metadata::backupGlobalsOnClass(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertTrue($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeBackupGlobalsOnMethod(): void + { + $metadata = Metadata::backupGlobalsOnMethod(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertTrue($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeBackupStaticPropertiesOnClass(): void + { + $metadata = Metadata::backupStaticPropertiesOnClass(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertTrue($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeBackupStaticPropertiesOnMethod(): void + { + $metadata = Metadata::backupStaticPropertiesOnMethod(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertTrue($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeBeforeClass(): void + { + $priority = 0; + + $metadata = Metadata::beforeClass($priority); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertTrue($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBeBefore(): void + { + $priority = 0; + + $metadata = Metadata::before($priority); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertTrue($metadata->isBefore()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBeCoversClass(): void + { + $metadata = Metadata::coversClass(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertTrue($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversNamespace(): void + { + $namespace = 'namespace'; + + $metadata = Metadata::coversNamespace($namespace); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertTrue($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame($namespace, $metadata->namespace()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversClassesThatExtendClass(): void + { + $metadata = Metadata::coversClassesThatExtendClass(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertTrue($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversClassesThatImplementInterface(): void + { + $metadata = Metadata::coversClassesThatImplementInterface(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertTrue($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->interfaceName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversFunction(): void + { + $metadata = Metadata::coversFunction('f'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertTrue($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('f', $metadata->functionName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversMethod(): void + { + $metadata = Metadata::coversMethod(self::class, 'testCanBeCoversMethod'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertTrue($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame('testCanBeCoversMethod', $metadata->methodName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversNothingOnMethod(): void + { + $metadata = Metadata::coversNothingOnMethod(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertTrue($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeCoversNothingOnClass(): void + { + $metadata = Metadata::coversNothingOnClass(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertTrue($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeCoversTrait(): void + { + $metadata = Metadata::coversTrait(ExampleTrait::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertTrue($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(ExampleTrait::class, $metadata->traitName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeDataProvider(): void + { + $metadata = Metadata::dataProvider(self::class, 'method', true); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertTrue($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame('method', $metadata->methodName()); + $this->assertTrue($metadata->validateArgumentCount()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeDependsOnClass(): void + { + $metadata = Metadata::dependsOnClass(self::class, false, false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertTrue($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertFalse($metadata->deepClone()); + $this->assertFalse($metadata->shallowClone()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeDependsOnMethod(): void + { + $metadata = Metadata::dependsOnMethod(self::class, 'method', false, false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertTrue($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame('method', $metadata->methodName()); + $this->assertFalse($metadata->deepClone()); + $this->assertFalse($metadata->shallowClone()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeDisableReturnValueGenerationForTestDoubles(): void + { + $metadata = Metadata::disableReturnValueGenerationForTestDoubles(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertTrue($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeDoesNotPerformAssertionsOnClass(): void + { + $metadata = Metadata::doesNotPerformAssertionsOnClass(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertTrue($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeDoesNotPerformAssertionsOnMethod(): void + { + $metadata = Metadata::doesNotPerformAssertionsOnMethod(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertTrue($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeExcludeGlobalVariableFromBackupOnClass(): void + { + $metadata = Metadata::excludeGlobalVariableFromBackupOnClass('variable'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertTrue($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('variable', $metadata->globalVariableName()); + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeExcludeGlobalVariableFromBackupOnMethod(): void + { + $metadata = Metadata::excludeGlobalVariableFromBackupOnMethod('variable'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertTrue($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('variable', $metadata->globalVariableName()); + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeExcludeStaticPropertyFromBackupOnClass(): void + { + $metadata = Metadata::excludeStaticPropertyFromBackupOnClass('class', 'property'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertTrue($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('class', $metadata->className()); + $this->assertSame('property', $metadata->propertyName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeExcludeStaticPropertyFromBackupOnMethod(): void + { + $metadata = Metadata::excludeStaticPropertyFromBackupOnMethod('class', 'property'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertTrue($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('class', $metadata->className()); + $this->assertSame('property', $metadata->propertyName()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeGroupOnClass(): void + { + $metadata = Metadata::groupOnClass('name'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertTrue($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('name', $metadata->groupName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeIgnoreDeprecationsOnClass(): void + { + $messagePattern = 'the-message-pattern'; + + $metadata = Metadata::ignoreDeprecationsOnClass($messagePattern); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertTrue($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + $this->assertSame($messagePattern, $metadata->messagePattern()); + } + + public function testCanBeIgnoreDeprecationsOnMethod(): void + { + $metadata = Metadata::ignoreDeprecationsOnMethod(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertTrue($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeIgnorePhpunitDeprecationsOnClass(): void + { + $metadata = Metadata::ignorePhpunitDeprecationsOnClass(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertTrue($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeIgnorePhpunitDeprecationsOnMethod(): void + { + $metadata = Metadata::ignorePhpunitDeprecationsOnMethod(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertTrue($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeIgnorePHPUnitWarnings(): void + { + $messagePattern = 'the-message-pattern'; + + $metadata = Metadata::ignorePHPUnitWarnings($messagePattern); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertTrue($metadata->isIgnorePhpunitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($messagePattern, $metadata->messagePattern()); + } + + public function testCanBeGroupOnMethod(): void + { + $metadata = Metadata::groupOnMethod('name'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertTrue($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('name', $metadata->groupName()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRunTestsInSeparateProcesses(): void + { + $metadata = Metadata::runTestsInSeparateProcesses(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertTrue($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRunInSeparateProcess(): void + { + $metadata = Metadata::runInSeparateProcess(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertTrue($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeTest(): void + { + $metadata = Metadata::test(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertTrue($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBePreCondition(): void + { + $priority = 0; + + $metadata = Metadata::preCondition($priority); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertTrue($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBePostCondition(): void + { + $priority = 0; + + $metadata = Metadata::postCondition($priority); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertTrue($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + $this->assertSame($priority, $metadata->priority()); + } + + public function testCanBePreserveGlobalStateOnClass(): void + { + $metadata = Metadata::preserveGlobalStateOnClass(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertTrue($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBePreserveGlobalStateOnMethod(): void + { + $metadata = Metadata::preserveGlobalStateOnMethod(false); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertTrue($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertFalse($metadata->enabled()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresMethodOnClass(): void + { + $metadata = Metadata::requiresMethodOnClass(self::class, __METHOD__); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertTrue($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame(__METHOD__, $metadata->methodName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresMethodOnMethod(): void + { + $metadata = Metadata::requiresMethodOnMethod(self::class, __METHOD__); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertTrue($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame(__METHOD__, $metadata->methodName()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresFunctionOnClass(): void + { + $metadata = Metadata::requiresFunctionOnClass('f'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertTrue($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('f', $metadata->functionName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresFunctionOnMethod(): void + { + $metadata = Metadata::requiresFunctionOnMethod('f'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertTrue($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('f', $metadata->functionName()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresOperatingSystemOnClass(): void + { + $metadata = Metadata::requiresOperatingSystemOnClass('Linux'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertTrue($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('Linux', $metadata->operatingSystem()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresOperatingSystemOnMethod(): void + { + $metadata = Metadata::requiresOperatingSystemOnMethod('Linux'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertTrue($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('Linux', $metadata->operatingSystem()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresOperatingSystemFamilyOnClass(): void + { + $metadata = Metadata::requiresOperatingSystemFamilyOnClass('Linux'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertTrue($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('Linux', $metadata->operatingSystemFamily()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresOperatingSystemFamilyOnMethod(): void + { + $metadata = Metadata::requiresOperatingSystemFamilyOnMethod('Linux'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertTrue($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('Linux', $metadata->operatingSystemFamily()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresPhpOnClass(): void + { + $metadata = Metadata::requiresPhpOnClass( + new ComparisonRequirement( + '8.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertTrue($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('>= 8.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresPhpOnMethod(): void + { + $metadata = Metadata::requiresPhpOnMethod( + new ComparisonRequirement( + '8.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertTrue($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('>= 8.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresPhpExtensionOnClass(): void + { + $metadata = Metadata::requiresPhpExtensionOnClass('test', null); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertTrue($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('test', $metadata->extension()); + $this->assertFalse($metadata->hasVersionRequirement()); + + $this->expectException(NoVersionRequirementException::class); + $metadata->versionRequirement(); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresPhpExtensionWithVersionOnClass(): void + { + $metadata = Metadata::requiresPhpExtensionOnClass( + 'test', + new ComparisonRequirement( + '1.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertTrue($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('test', $metadata->extension()); + $this->assertTrue($metadata->hasVersionRequirement()); + $this->assertSame('>= 1.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresPhpExtensionOnMethod(): void + { + $metadata = Metadata::requiresPhpExtensionOnMethod('test', null); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertTrue($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('test', $metadata->extension()); + $this->assertFalse($metadata->hasVersionRequirement()); + + $this->expectException(NoVersionRequirementException::class); + $metadata->versionRequirement(); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresPhpExtensionWithVersionOnMethod(): void + { + $metadata = Metadata::requiresPhpExtensionOnMethod( + 'test', + new ComparisonRequirement( + '1.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertTrue($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('test', $metadata->extension()); + $this->assertTrue($metadata->hasVersionRequirement()); + $this->assertSame('>= 1.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresPhpunitOnClass(): void + { + $metadata = Metadata::requiresPhpunitOnClass( + new ComparisonRequirement( + '10.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertTrue($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('>= 10.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresPhpunitExtensionOnClass(): void + { + $metadata = Metadata::requiresPhpunitExtensionOnClass(SomeExtension::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertTrue($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(SomeExtension::class, $metadata->extensionClass()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresPhpunitOnMethod(): void + { + $metadata = Metadata::requiresPhpunitOnMethod( + new ComparisonRequirement( + '10.0.0', + new VersionComparisonOperator('>='), + ), + ); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertTrue($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('>= 10.0.0', $metadata->versionRequirement()->asString()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresPhpunitExtensionOnMethod(): void + { + $metadata = Metadata::requiresPhpunitExtensionOnMethod(SomeExtension::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertTrue($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(SomeExtension::class, $metadata->extensionClass()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresEnvironmentVariableOnMethod(): void + { + $metadata = Metadata::requiresEnvironmentVariableOnMethod('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertTrue($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->environmentVariableName()); + $this->assertSame('bar', $metadata->value()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeRequiresEnvironmentVariableOnClass(): void + { + $metadata = Metadata::requiresEnvironmentVariableOnClass('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertTrue($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->environmentVariableName()); + $this->assertSame('bar', $metadata->value()); + + $this->assertFalse($metadata->isMethodLevel()); + $this->assertTrue($metadata->isClassLevel()); + } + + public function testCanBeWithEnvironmentVariableOnMethod(): void + { + $metadata = Metadata::withEnvironmentVariableOnMethod('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertTrue($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->environmentVariableName()); + $this->assertSame('bar', $metadata->value()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeWithEnvironmentVariableOnClass(): void + { + $metadata = Metadata::withEnvironmentVariableOnClass('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertTrue($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->environmentVariableName()); + $this->assertSame('bar', $metadata->value()); + + $this->assertFalse($metadata->isMethodLevel()); + $this->assertTrue($metadata->isClassLevel()); + } + + public function testCanBeRequiresSettingOnClass(): void + { + $metadata = Metadata::requiresSettingOnClass('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertTrue($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->setting()); + $this->assertSame('bar', $metadata->value()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeRequiresSettingOnMethod(): void + { + $metadata = Metadata::requiresSettingOnMethod('foo', 'bar'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertTrue($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('foo', $metadata->setting()); + $this->assertSame('bar', $metadata->value()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeTestDoxOnClass(): void + { + $metadata = Metadata::testDoxOnClass('text'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertTrue($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('text', $metadata->text()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeTestDoxOnMethod(): void + { + $metadata = Metadata::testDoxOnMethod('text'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertTrue($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('text', $metadata->text()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeTestDoxFormatterOnMethod(): void + { + $metadata = Metadata::testDoxFormatter(self::class, 'method'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertTrue($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame('method', $metadata->methodName()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeTestWith(): void + { + $metadata = Metadata::testWith(['a', 'b']); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertTrue($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(['a', 'b'], $metadata->data()); + $this->assertFalse($metadata->hasName()); + $this->assertNull($metadata->name()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } + + public function testCanBeUsesNamespace(): void + { + $namespace = 'namespace'; + + $metadata = Metadata::usesNamespace($namespace); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertTrue($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame($namespace, $metadata->namespace()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesClass(): void + { + $metadata = Metadata::usesClass(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertTrue($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesClassesThatExtendClass(): void + { + $metadata = Metadata::usesClassesThatExtendClass(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertTrue($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesClassesThatImplementInterface(): void + { + $metadata = Metadata::usesClassesThatImplementInterface(self::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertTrue($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->interfaceName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesFunction(): void + { + $metadata = Metadata::usesFunction('f'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertTrue($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame('f', $metadata->functionName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesMethod(): void + { + $metadata = Metadata::usesMethod(self::class, 'testCanBeUsesMethod'); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertTrue($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(self::class, $metadata->className()); + $this->assertSame('testCanBeUsesMethod', $metadata->methodName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeUsesTrait(): void + { + $metadata = Metadata::usesTrait(ExampleTrait::class); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertTrue($metadata->isUsesTrait()); + $this->assertFalse($metadata->isWithoutErrorHandler()); + + $this->assertSame(ExampleTrait::class, $metadata->traitName()); + + $this->assertTrue($metadata->isClassLevel()); + $this->assertFalse($metadata->isMethodLevel()); + } + + public function testCanBeWithoutErrorHandler(): void + { + $metadata = Metadata::withoutErrorHandler(); + + $this->assertFalse($metadata->isAfter()); + $this->assertFalse($metadata->isAfterClass()); + $this->assertFalse($metadata->isAllowMockObjectsWithoutExpectations()); + $this->assertFalse($metadata->isBackupGlobals()); + $this->assertFalse($metadata->isBackupStaticProperties()); + $this->assertFalse($metadata->isBeforeClass()); + $this->assertFalse($metadata->isBefore()); + $this->assertFalse($metadata->isCoversNamespace()); + $this->assertFalse($metadata->isCoversClass()); + $this->assertFalse($metadata->isCoversClassesThatExtendClass()); + $this->assertFalse($metadata->isCoversClassesThatImplementInterface()); + $this->assertFalse($metadata->isCoversFunction()); + $this->assertFalse($metadata->isCoversMethod()); + $this->assertFalse($metadata->isCoversNothing()); + $this->assertFalse($metadata->isCoversTrait()); + $this->assertFalse($metadata->isDataProvider()); + $this->assertFalse($metadata->isDependsOnClass()); + $this->assertFalse($metadata->isDependsOnMethod()); + $this->assertFalse($metadata->isDisableReturnValueGenerationForTestDoubles()); + $this->assertFalse($metadata->isDoesNotPerformAssertions()); + $this->assertFalse($metadata->isExcludeGlobalVariableFromBackup()); + $this->assertFalse($metadata->isExcludeStaticPropertyFromBackup()); + $this->assertFalse($metadata->isGroup()); + $this->assertFalse($metadata->isIgnoreDeprecations()); + $this->assertFalse($metadata->isIgnorePhpunitDeprecations()); + $this->assertFalse($metadata->isIgnorePHPUnitWarnings()); + $this->assertFalse($metadata->isRunInSeparateProcess()); + $this->assertFalse($metadata->isRunTestsInSeparateProcesses()); + $this->assertFalse($metadata->isTest()); + $this->assertFalse($metadata->isPreCondition()); + $this->assertFalse($metadata->isPostCondition()); + $this->assertFalse($metadata->isPreserveGlobalState()); + $this->assertFalse($metadata->isRequiresMethod()); + $this->assertFalse($metadata->isRequiresFunction()); + $this->assertFalse($metadata->isRequiresOperatingSystem()); + $this->assertFalse($metadata->isRequiresOperatingSystemFamily()); + $this->assertFalse($metadata->isRequiresPhp()); + $this->assertFalse($metadata->isRequiresPhpExtension()); + $this->assertFalse($metadata->isRequiresPhpunit()); + $this->assertFalse($metadata->isRequiresPhpunitExtension()); + $this->assertFalse($metadata->isRequiresEnvironmentVariable()); + $this->assertFalse($metadata->isWithEnvironmentVariable()); + $this->assertFalse($metadata->isRequiresSetting()); + $this->assertFalse($metadata->isTestDox()); + $this->assertFalse($metadata->isTestDoxFormatter()); + $this->assertFalse($metadata->isTestWith()); + $this->assertFalse($metadata->isUsesNamespace()); + $this->assertFalse($metadata->isUsesClass()); + $this->assertFalse($metadata->isUsesClassesThatExtendClass()); + $this->assertFalse($metadata->isUsesClassesThatImplementInterface()); + $this->assertFalse($metadata->isUsesFunction()); + $this->assertFalse($metadata->isUsesMethod()); + $this->assertFalse($metadata->isUsesTrait()); + $this->assertTrue($metadata->isWithoutErrorHandler()); + + $this->assertTrue($metadata->isMethodLevel()); + $this->assertFalse($metadata->isClassLevel()); + } +} diff --git a/tests/unit/Metadata/Parser/AttributeParserTest.php b/tests/unit/Metadata/Parser/AttributeParserTest.php new file mode 100644 index 00000000000..b9b1ecb250b --- /dev/null +++ b/tests/unit/Metadata/Parser/AttributeParserTest.php @@ -0,0 +1,157 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\AfterClass; +use PHPUnit\Framework\Attributes\AllowMockObjectsWithoutExpectations; +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\BackupStaticProperties; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\CoversClassesThatExtendClass; +use PHPUnit\Framework\Attributes\CoversClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\CoversFunction; +use PHPUnit\Framework\Attributes\CoversMethod; +use PHPUnit\Framework\Attributes\CoversNamespace; +use PHPUnit\Framework\Attributes\CoversNothing; +use PHPUnit\Framework\Attributes\CoversTrait; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Depends; +use PHPUnit\Framework\Attributes\DependsExternal; +use PHPUnit\Framework\Attributes\DependsExternalUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsExternalUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsOnClass; +use PHPUnit\Framework\Attributes\DependsOnClassUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsOnClassUsingShallowClone; +use PHPUnit\Framework\Attributes\DependsUsingDeepClone; +use PHPUnit\Framework\Attributes\DependsUsingShallowClone; +use PHPUnit\Framework\Attributes\DoesNotPerformAssertions; +use PHPUnit\Framework\Attributes\ExcludeGlobalVariableFromBackup; +use PHPUnit\Framework\Attributes\ExcludeStaticPropertyFromBackup; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\IgnorePhpunitWarnings; +use PHPUnit\Framework\Attributes\Large; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\PostCondition; +use PHPUnit\Framework\Attributes\PreCondition; +use PHPUnit\Framework\Attributes\PreserveGlobalState; +use PHPUnit\Framework\Attributes\RequiresEnvironmentVariable; +use PHPUnit\Framework\Attributes\RequiresFunction; +use PHPUnit\Framework\Attributes\RequiresMethod; +use PHPUnit\Framework\Attributes\RequiresOperatingSystem; +use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily; +use PHPUnit\Framework\Attributes\RequiresPhp; +use PHPUnit\Framework\Attributes\RequiresPhpExtension; +use PHPUnit\Framework\Attributes\RequiresPhpunit; +use PHPUnit\Framework\Attributes\RequiresPhpunitExtension; +use PHPUnit\Framework\Attributes\RequiresSetting; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\Attributes\TestDoxFormatter; +use PHPUnit\Framework\Attributes\TestDoxFormatterExternal; +use PHPUnit\Framework\Attributes\TestWith; +use PHPUnit\Framework\Attributes\TestWithJson; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\Attributes\UsesClassesThatExtendClass; +use PHPUnit\Framework\Attributes\UsesClassesThatImplementInterface; +use PHPUnit\Framework\Attributes\UsesFunction; +use PHPUnit\Framework\Attributes\UsesMethod; +use PHPUnit\Framework\Attributes\UsesNamespace; +use PHPUnit\Framework\Attributes\UsesTrait; +use PHPUnit\Framework\Attributes\WithEnvironmentVariable; +use PHPUnit\Framework\Attributes\WithoutErrorHandler; +use PHPUnit\Metadata\DisableReturnValueGenerationForTestDoubles; +use PHPUnit\Metadata\InvalidAttributeException; + +#[CoversClass(AttributeParser::class)] +#[CoversClass(AllowMockObjectsWithoutExpectations::class)] +#[CoversClass(AfterClass::class)] +#[CoversClass(After::class)] +#[CoversClass(BackupGlobals::class)] +#[CoversClass(BackupStaticProperties::class)] +#[CoversClass(BeforeClass::class)] +#[CoversClass(Before::class)] +#[CoversClass(CoversClass::class)] +#[CoversClass(CoversClassesThatExtendClass::class)] +#[CoversClass(CoversClassesThatImplementInterface::class)] +#[CoversClass(CoversFunction::class)] +#[CoversClass(CoversMethod::class)] +#[CoversClass(CoversNamespace::class)] +#[CoversClass(CoversNothing::class)] +#[CoversClass(CoversTrait::class)] +#[CoversClass(DataProviderExternal::class)] +#[CoversClass(DataProvider::class)] +#[CoversClass(DependsExternal::class)] +#[CoversClass(DependsExternalUsingDeepClone::class)] +#[CoversClass(DependsExternalUsingShallowClone::class)] +#[CoversClass(DependsOnClass::class)] +#[CoversClass(DependsOnClassUsingDeepClone::class)] +#[CoversClass(DependsOnClassUsingShallowClone::class)] +#[CoversClass(Depends::class)] +#[CoversClass(DependsUsingDeepClone::class)] +#[CoversClass(DependsUsingShallowClone::class)] +#[CoversClass(DisableReturnValueGenerationForTestDoubles::class)] +#[CoversClass(DoesNotPerformAssertions::class)] +#[CoversClass(ExcludeGlobalVariableFromBackup::class)] +#[CoversClass(ExcludeStaticPropertyFromBackup::class)] +#[CoversClass(Group::class)] +#[CoversClass(InvalidAttributeException::class)] +#[CoversClass(Large::class)] +#[CoversClass(Medium::class)] +#[CoversClass(PostCondition::class)] +#[CoversClass(PreCondition::class)] +#[CoversClass(PreserveGlobalState::class)] +#[CoversClass(RequiresFunction::class)] +#[CoversClass(RequiresMethod::class)] +#[CoversClass(RequiresOperatingSystemFamily::class)] +#[CoversClass(RequiresOperatingSystem::class)] +#[CoversClass(RequiresPhpExtension::class)] +#[CoversClass(RequiresPhp::class)] +#[CoversClass(RequiresPhpunit::class)] +#[CoversClass(RequiresPhpunitExtension::class)] +#[CoversClass(RequiresEnvironmentVariable::class)] +#[CoversClass(RequiresSetting::class)] +#[CoversClass(RunInSeparateProcess::class)] +#[CoversClass(RunTestsInSeparateProcesses::class)] +#[CoversClass(Small::class)] +#[CoversClass(TestDox::class)] +#[CoversClass(TestDoxFormatter::class)] +#[CoversClass(TestDoxFormatterExternal::class)] +#[CoversClass(Test::class)] +#[CoversClass(TestWithJson::class)] +#[CoversClass(TestWith::class)] +#[CoversClass(Ticket::class)] +#[CoversClass(UsesClass::class)] +#[CoversClass(UsesClassesThatExtendClass::class)] +#[CoversClass(UsesClassesThatImplementInterface::class)] +#[CoversClass(UsesFunction::class)] +#[CoversClass(UsesMethod::class)] +#[CoversClass(UsesNamespace::class)] +#[CoversClass(UsesTrait::class)] +#[CoversClass(WithEnvironmentVariable::class)] +#[CoversClass(WithoutErrorHandler::class)] +#[CoversClass(IgnorePhpunitWarnings::class)] +#[Small] +#[Group('metadata')] +#[Group('metadata/attributes')] +final class AttributeParserTest extends AttributeParserTestCase +{ + protected function parser(): Parser + { + return new AttributeParser; + } +} diff --git a/tests/unit/Metadata/Parser/AttributeParserTestCase.php b/tests/unit/Metadata/Parser/AttributeParserTestCase.php new file mode 100644 index 00000000000..f5ef0a60058 --- /dev/null +++ b/tests/unit/Metadata/Parser/AttributeParserTestCase.php @@ -0,0 +1,1237 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use function assert; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\DependsOnClass; +use PHPUnit\Metadata\DependsOnMethod; +use PHPUnit\Metadata\InvalidAttributeException; +use PHPUnit\Metadata\RequiresEnvironmentVariable; +use PHPUnit\Metadata\RequiresPhp; +use PHPUnit\Metadata\RequiresPhpExtension; +use PHPUnit\Metadata\RequiresPhpunit; +use PHPUnit\Metadata\RequiresPhpunitExtension; +use PHPUnit\Metadata\RequiresSetting; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\ConstraintRequirement; +use PHPUnit\Metadata\WithEnvironmentVariable; +use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnClassTest; +use PHPUnit\TestFixture\Metadata\Attribute\AllowMockObjectsWithoutExpectationsOnMethodTest; +use PHPUnit\TestFixture\Metadata\Attribute\AnotherTest; +use PHPUnit\TestFixture\Metadata\Attribute\BackupGlobalsTest; +use PHPUnit\TestFixture\Metadata\Attribute\BackupStaticPropertiesTest; +use PHPUnit\TestFixture\Metadata\Attribute\CoversNothingTest; +use PHPUnit\TestFixture\Metadata\Attribute\CoversTest; +use PHPUnit\TestFixture\Metadata\Attribute\DependencyTest; +use PHPUnit\TestFixture\Metadata\Attribute\DisableReturnValueGenerationForTestDoublesTest; +use PHPUnit\TestFixture\Metadata\Attribute\DoesNotPerformAssertionsTest; +use PHPUnit\TestFixture\Metadata\Attribute\DuplicateSmallAttributeTest; +use PHPUnit\TestFixture\Metadata\Attribute\DuplicateTestAttributeTest; +use PHPUnit\TestFixture\Metadata\Attribute\Example; +use PHPUnit\TestFixture\Metadata\Attribute\ExampleTrait; +use PHPUnit\TestFixture\Metadata\Attribute\GroupTest; +use PHPUnit\TestFixture\Metadata\Attribute\IgnoreDeprecationsClassTest; +use PHPUnit\TestFixture\Metadata\Attribute\IgnoreDeprecationsMethodTest; +use PHPUnit\TestFixture\Metadata\Attribute\IgnorePhpunitDeprecationsClassTest; +use PHPUnit\TestFixture\Metadata\Attribute\IgnorePhpunitDeprecationsMethodTest; +use PHPUnit\TestFixture\Metadata\Attribute\IgnorePhpunitWarningsTest; +use PHPUnit\TestFixture\Metadata\Attribute\LargeTest; +use PHPUnit\TestFixture\Metadata\Attribute\MediumTest; +use PHPUnit\TestFixture\Metadata\Attribute\NonPhpunitAttributeTest; +use PHPUnit\TestFixture\Metadata\Attribute\PhpunitAttributeThatDoesNotExistTest; +use PHPUnit\TestFixture\Metadata\Attribute\PreserveGlobalStateTest; +use PHPUnit\TestFixture\Metadata\Attribute\ProcessIsolationTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresEnvironmentVariableTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresFunctionTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresMethodTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresOperatingSystemFamilyTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresOperatingSystemTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresPhpExtensionTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresPhpTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresPhpunitExtensionTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresPhpunitTest; +use PHPUnit\TestFixture\Metadata\Attribute\RequiresSettingTest; +use PHPUnit\TestFixture\Metadata\Attribute\SmallTest; +use PHPUnit\TestFixture\Metadata\Attribute\TestDoxTest; +use PHPUnit\TestFixture\Metadata\Attribute\TestWithTest; +use PHPUnit\TestFixture\Metadata\Attribute\UsesTest; +use PHPUnit\TestFixture\Metadata\Attribute\WithEnvironmentVariableTest; +use PHPUnit\TestFixture\Metadata\Attribute\WithoutErrorHandlerTest; + +abstract class AttributeParserTestCase extends TestCase +{ + #[TestDox('Parses #[AllowMockObjectsWithoutExpectations] attribute on class')] + public function test_parses_AllowMockObjectsWithoutExpectations_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(AllowMockObjectsWithoutExpectationsOnClassTest::class)->isAllowMockObjectsWithoutExpectations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isAllowMockObjectsWithoutExpectations()); + } + + #[TestDox('Parses #[BackupGlobals] attribute on class')] + public function test_parses_BackupGlobals_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(BackupGlobalsTest::class)->isBackupGlobals(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBackupGlobals()); + $this->assertTrue($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[BackupStaticProperties] attribute on class')] + public function test_parses_BackupStaticProperties_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(BackupStaticPropertiesTest::class)->isBackupStaticProperties(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBackupStaticProperties()); + $this->assertTrue($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[CoversNamespace] attribute on class')] + public function test_parses_CoversNamespace_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversNamespace(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversNamespace()); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute', $metadata->asArray()[0]->namespace()); + } + + #[TestDox('Parses #[CoversClass] attribute on class')] + public function test_parses_CoversClass_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversClass()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + } + + #[TestDox('Parses #[CoversClassesThatExtendClass] attribute on class')] + public function test_parses_CoversClassesThatExtendClass_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversClassesThatExtendClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversClassesThatExtendClass()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + } + + #[TestDox('Parses #[CoversClassesThatImplementInterface] attribute on class')] + public function test_parses_CoversClassesThatImplementInterface_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversClassesThatImplementInterface(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversClassesThatImplementInterface()); + $this->assertSame(Example::class, $metadata->asArray()[0]->interfaceName()); + } + + #[TestDox('Parses #[CoversTrait] attribute on class')] + public function test_parses_CoversTrait_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversTrait(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversTrait()); + $this->assertSame(ExampleTrait::class, $metadata->asArray()[0]->traitName()); + } + + #[TestDox('Parses #[CoversFunction] attribute on class')] + public function test_parses_CoversFunction_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversFunction(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversFunction()); + $this->assertSame('f', $metadata->asArray()[0]->functionName()); + } + + #[TestDox('Parses #[CoversMethod] attribute on class')] + public function test_parses_CoversMethod_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversTest::class)->isCoversMethod(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversMethod()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + $this->assertSame('method', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[CoversNothing] attribute on class')] + public function test_parses_CoversNothing_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(CoversNothingTest::class)->isCoversNothing(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversNothing()); + } + + #[TestDox('Parses #[DisableReturnValueGenerationForTestDoubles] attribute on class')] + public function test_parses_DisableReturnValueGenerationForTestDoubles_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(DisableReturnValueGenerationForTestDoublesTest::class)->isDisableReturnValueGenerationForTestDoubles(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isDisableReturnValueGenerationForTestDoubles()); + } + + #[TestDox('Parses #[DoesNotPerformAssertions] attribute on class')] + public function test_parses_DoesNotPerformAssertions_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(DoesNotPerformAssertionsTest::class)->isDoesNotPerformAssertions(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isDoesNotPerformAssertions()); + } + + #[TestDox('Parses #[ExcludeGlobalVariableFromBackup] attribute on class')] + public function test_parses_ExcludeGlobalVariableFromBackup_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(BackupGlobalsTest::class)->isExcludeGlobalVariableFromBackup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isExcludeGlobalVariableFromBackup()); + $this->assertSame('foo', $metadata->asArray()[0]->globalVariableName()); + } + + #[TestDox('Parses #[ExcludeStaticPropertyFromBackup] attribute on class')] + public function test_parses_ExcludeStaticPropertyFromBackup_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(BackupStaticPropertiesTest::class)->isExcludeStaticPropertyFromBackup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isExcludeStaticPropertyFromBackup()); + $this->assertSame('className', $metadata->asArray()[0]->className()); + $this->assertSame('propertyName', $metadata->asArray()[0]->propertyName()); + } + + #[TestDox('Parses #[Group] attribute on class')] + public function test_parses_Group_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(GroupTest::class)->isGroup(); + + $this->assertCount(2, $metadata); + $this->assertTrue($metadata->asArray()[0]->isGroup()); + $this->assertSame('group', $metadata->asArray()[0]->groupName()); + } + + #[TestDox('Parses #[Large] attribute on class')] + public function test_parses_Large_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(LargeTest::class)->isGroup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isGroup()); + $this->assertSame('large', $metadata->asArray()[0]->groupName()); + } + + #[TestDox('Parses #[Medium] attribute on class')] + public function test_parses_Medium_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(MediumTest::class)->isGroup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isGroup()); + $this->assertSame('medium', $metadata->asArray()[0]->groupName()); + } + + #[TestDox('Parses #[IgnoreDeprecations] attribute on class')] + public function test_parses_IgnoreDeprecations_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(IgnoreDeprecationsClassTest::class)->isIgnoreDeprecations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isIgnoreDeprecations()); + } + + #[TestDox('Parses #[IgnorePhpunitDeprecations] attribute on class')] + public function test_parses_IgnorePhpunitDeprecations_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(IgnorePhpunitDeprecationsClassTest::class)->isIgnorePhpunitDeprecations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isIgnorePhpunitDeprecations()); + } + + #[TestDox('Parses #[PreserveGlobalState] attribute on class')] + public function test_parses_PreserveGlobalState_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(PreserveGlobalStateTest::class)->isPreserveGlobalState(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isPreserveGlobalState()); + $this->assertTrue($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[RequiresMethod] attribute on class')] + public function test_parses_RequiresMethod_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresMethodTest::class)->isRequiresMethod(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresMethod()); + $this->assertSame('ClassName', $metadata->asArray()[0]->className()); + $this->assertSame('methodName', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[RequiresFunction] attribute on class')] + public function test_parses_RequiresFunction_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresFunctionTest::class)->isRequiresFunction(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresFunction()); + $this->assertSame('f', $metadata->asArray()[0]->functionName()); + } + + #[TestDox('Parses #[RequiresOperatingSystem] attribute on class')] + public function test_parses_RequiresOperatingSystem_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresOperatingSystemTest::class)->isRequiresOperatingSystem(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresOperatingSystem()); + $this->assertSame('Linux', $metadata->asArray()[0]->operatingSystem()); + } + + #[TestDox('Parses #[RequiresOperatingSystemFamily] attribute on class')] + public function test_parses_RequiresOperatingSystemFamily_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresOperatingSystemFamilyTest::class)->isRequiresOperatingSystemFamily(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresOperatingSystemFamily()); + $this->assertSame('Linux', $metadata->asArray()[0]->operatingSystemFamily()); + } + + #[TestDox('Parses #[RequiresPhp] attribute on class')] + public function test_parses_RequiresPhp_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresPhpTest::class)->isRequiresPhp(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhp()); + + assert($requirement instanceof RequiresPhp); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ConstraintRequirement); + + $this->assertSame('8.0.0', $versionRequirement->asString()); + } + + #[TestDox('Parses #[RequiresPhpExtension] attribute on class')] + public function test_parses_RequiresPhpExtension_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresPhpExtensionTest::class)->isRequiresPhpExtension(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresPhpExtension()); + $this->assertSame('foo', $metadata->asArray()[0]->extension()); + $this->assertTrue($metadata->asArray()[0]->hasVersionRequirement()); + $this->assertSame('>= 1.0', $metadata->asArray()[0]->versionRequirement()->asString()); + } + + #[TestDox('Parses #[RequiresPhpunit] attribute on class')] + public function test_parses_RequiresPhpunit_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresPhpunitTest::class)->isRequiresPhpunit(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhpunit()); + + assert($requirement instanceof RequiresPhpunit); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ComparisonRequirement); + + $this->assertSame('>= 10.0.0', $versionRequirement->asString()); + } + + #[TestDox('Parses #[RequiresPhpunitExtension] attribute on class')] + public function test_parses_RequiresPhpunitExtension_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresPhpunitExtensionTest::class)->isRequiresPhpunitExtension(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhpunitExtension()); + + assert($requirement instanceof RequiresPhpunitExtension); + + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\SomeExtension', $requirement->extensionClass()); + } + + #[TestDox('Parses #[RequiresEnvironmentVariable] attribute on class')] + public function test_parses_RequiresEnvironmentVariable_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresEnvironmentVariableTest::class)->isRequiresEnvironmentVariable(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresEnvironmentVariable()); + + assert($requirement instanceof RequiresEnvironmentVariable); + + $this->assertSame('foo', $requirement->environmentVariableName()); + $this->assertSame('bar', $requirement->value()); + } + + #[TestDox('Parses #[WithEnvironmentVariable] attribute on class')] + public function test_parses_WithEnvironmentVariable_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(WithEnvironmentVariableTest::class)->isWithEnvironmentVariable(); + + $this->assertCount(1, $metadata); + + $withEnvironmentVariable = $metadata->asArray()[0]; + $this->assertTrue($withEnvironmentVariable->isWithEnvironmentVariable()); + assert($withEnvironmentVariable instanceof WithEnvironmentVariable); + $this->assertSame('foo', $withEnvironmentVariable->environmentVariableName()); + $this->assertSame('bar', $withEnvironmentVariable->value()); + } + + #[TestDox('Parses #[RequiresSetting] attribute on class')] + public function test_parses_RequiresSetting_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(RequiresSettingTest::class)->isRequiresSetting(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresSetting()); + + assert($requirement instanceof RequiresSetting); + + $this->assertSame('setting', $requirement->setting()); + $this->assertSame('value', $requirement->value()); + } + + #[TestDox('Parses #[RunTestsInSeparateProcesses] attribute on class')] + public function test_parses_RunTestsInSeparateProcesses_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(ProcessIsolationTest::class)->isRunTestsInSeparateProcesses(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRunTestsInSeparateProcesses()); + } + + #[TestDox('Parses #[Small] attribute on class')] + public function test_parses_Small_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(SmallTest::class)->isGroup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isGroup()); + $this->assertSame('small', $metadata->asArray()[0]->groupName()); + } + + #[TestDox('Parses #[TestDox] attribute on class')] + public function test_parses_TestDox_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(TestDoxTest::class)->isTestDox(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestDox()); + $this->assertSame('text', $metadata->asArray()[0]->text()); + } + + #[TestDox('Parses #[Ticket] attribute on class')] + public function test_parses_Ticket_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(GroupTest::class)->isGroup(); + + $this->assertCount(2, $metadata); + $this->assertTrue($metadata->asArray()[1]->isGroup()); + $this->assertSame('ticket', $metadata->asArray()[1]->groupName()); + } + + #[TestDox('Parses #[UsesNamespace] attribute on class')] + public function test_parses_UsesNamespace_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesNamespace(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesNamespace()); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute', $metadata->asArray()[0]->namespace()); + } + + #[TestDox('Parses #[UsesClass] attribute on class')] + public function test_parses_UsesClass_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesClass()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + } + + #[TestDox('Parses #[UsesClassesThatExtendClass] attribute on class')] + public function test_parses_UsesClassesThatExtendClass_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesClassesThatExtendClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesClassesThatExtendClass()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + } + + #[TestDox('Parses #[UsesClassesThatImplementInterface] attribute on class')] + public function test_parses_UsesClassesThatImplementInterface_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesClassesThatImplementInterface(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesClassesThatImplementInterface()); + $this->assertSame(Example::class, $metadata->asArray()[0]->interfaceName()); + } + + #[TestDox('Parses #[UsesTrait] attribute on class')] + public function test_parses_UsesTrait_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesTrait(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesTrait()); + $this->assertSame(ExampleTrait::class, $metadata->asArray()[0]->traitName()); + } + + #[TestDox('Parses #[UsesFunction] attribute on class')] + public function test_parses_UsesFunction_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesFunction(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesFunction()); + $this->assertSame('f', $metadata->asArray()[0]->functionName()); + } + + #[TestDox('Parses #[UsesMethod] attribute on class')] + public function test_parses_UsesMethod_attribute_on_class(): void + { + $metadata = $this->parser()->forClass(UsesTest::class)->isUsesMethod(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isUsesMethod()); + $this->assertSame(Example::class, $metadata->asArray()[0]->className()); + $this->assertSame('method', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[After] attribute on class')] + public function test_parses_After_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'afterTest')->isAfter(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isAfter()); + } + + #[TestDox('Parses #[AfterClass] attribute on class')] + public function test_parses_AfterClass_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'afterTests')->isAfterClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isAfterClass()); + } + + #[TestDox('Parses #[AllowMockObjectsWithoutExpectations] attribute on method')] + public function test_parses_AllowMockObjectsWithoutExpectations_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(AllowMockObjectsWithoutExpectationsOnMethodTest::class, 'testOne')->isAllowMockObjectsWithoutExpectations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isAllowMockObjectsWithoutExpectations()); + } + + #[TestDox('Parses #[BackupGlobals] attribute on method')] + public function test_parses_BackupGlobals_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(BackupGlobalsTest::class, 'testOne')->isBackupGlobals(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBackupGlobals()); + $this->assertFalse($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[BackupStaticProperties] attribute on method')] + public function test_parses_BackupStaticProperties_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(BackupStaticPropertiesTest::class, 'testOne')->isBackupStaticProperties(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBackupStaticProperties()); + $this->assertFalse($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[Before] attribute on method')] + public function test_parses_Before_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'beforeTest')->isBefore(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBefore()); + } + + #[TestDox('Parses #[BeforeClass] attribute on method')] + public function test_parses_BeforeClass_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'beforeTests')->isBeforeClass(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isBeforeClass()); + } + + #[TestDox('Parses #[CoversNothing] attribute on method')] + public function test_parses_CoversNothing_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(CoversNothingTest::class, 'testOne')->isCoversNothing(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isCoversNothing()); + } + + #[TestDox('Parses #[DataProvider] attribute on method')] + public function test_parses_DataProvider_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'testWithDataProvider')->isDataProvider(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isDataProvider()); + $this->assertSame(SmallTest::class, $metadata->asArray()[0]->className()); + $this->assertSame('provider', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[DataProviderExternal] attribute on method')] + public function test_parses_DataProviderExternal_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'testWithDataProviderExternal')->isDataProvider(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isDataProvider()); + $this->assertSame(SmallTest::class, $metadata->asArray()[0]->className()); + $this->assertSame('provider', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[Depends] attribute on method')] + public function test_parses_Depends_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testOne')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(DependencyTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertFalse($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsUsingDeepClone] attribute on method')] + public function test_parses_DependsUsingDeepClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testTwo')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(DependencyTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertTrue($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsUsingShallowClone] attribute on method')] + public function test_parses_DependsUsingShallowClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testThree')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(DependencyTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertFalse($depends->deepClone()); + $this->assertTrue($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsExternal] attribute on method')] + public function test_parses_DependsExternal_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testFour')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertFalse($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsExternalUsingDeepClone] attribute on method')] + public function test_parses_DependsExternalUsingDeepClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testFive')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertTrue($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsExternalUsingShallowClone] attribute on method')] + public function test_parses_DependsExternalUsingShallowClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testSix')->isDependsOnMethod(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnMethod); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertSame('testOne', $depends->methodName()); + $this->assertFalse($depends->deepClone()); + $this->assertTrue($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsOnClass] attribute on method')] + public function test_parses_DependsOnClass_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testSeven')->isDependsOnClass(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnClass); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertFalse($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsOnClassUsingDeepClone] attribute on method')] + public function test_parses_DependsOnClassUsingDeepClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testEight')->isDependsOnClass(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnClass); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertTrue($depends->deepClone()); + $this->assertFalse($depends->shallowClone()); + } + + #[TestDox('Parses #[DependsOnClassUsingShallowClone] attribute on method')] + public function test_parses_DependsOnClassUsingShallowClone_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DependencyTest::class, 'testNine')->isDependsOnClass(); + + $this->assertCount(1, $metadata); + + $depends = $metadata->asArray()[0]; + + assert($depends instanceof DependsOnClass); + + $this->assertSame(AnotherTest::class, $depends->className()); + $this->assertFalse($depends->deepClone()); + $this->assertTrue($depends->shallowClone()); + } + + #[TestDox('Parses #[DoesNotPerformAssertions] attribute on method')] + public function test_parses_DoesNotPerformAssertions_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(DoesNotPerformAssertionsTest::class, 'testOne')->isDoesNotPerformAssertions(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isDoesNotPerformAssertions()); + } + + #[TestDox('Parses #[ExcludeGlobalVariableFromBackup] attribute on method')] + public function test_parses_ExcludeGlobalVariableFromBackup_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(BackupGlobalsTest::class, 'testOne')->isExcludeGlobalVariableFromBackup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isExcludeGlobalVariableFromBackup()); + $this->assertSame('bar', $metadata->asArray()[0]->globalVariableName()); + } + + #[TestDox('Parses #[ExcludeStaticPropertyFromBackup] attribute on method')] + public function test_parses_ExcludeStaticPropertyFromBackup_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(BackupStaticPropertiesTest::class, 'testOne')->isExcludeStaticPropertyFromBackup(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isExcludeStaticPropertyFromBackup()); + $this->assertSame('anotherClassName', $metadata->asArray()[0]->className()); + $this->assertSame('propertyName', $metadata->asArray()[0]->propertyName()); + } + + #[TestDox('Parses #[Group] attribute on method')] + public function test_parses_Group_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(GroupTest::class, 'testOne')->isGroup(); + + $this->assertCount(2, $metadata); + $this->assertTrue($metadata->asArray()[0]->isGroup()); + $this->assertSame('another-group', $metadata->asArray()[0]->groupName()); + } + + #[TestDox('Parses #[IgnoreDeprecations] attribute on method')] + public function test_parses_IgnoreDeprecations_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(IgnoreDeprecationsMethodTest::class, 'testOne')->isIgnoreDeprecations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isIgnoreDeprecations()); + } + + #[TestDox('Parses #[IgnorePhpunitDeprecations] attribute on method')] + public function test_parses_IgnorePhpunitDeprecations_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(IgnorePhpunitDeprecationsMethodTest::class, 'testOne')->isIgnorePhpunitDeprecations(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isIgnorePhpunitDeprecations()); + } + + #[TestDox('Parses #[IgnorePhpunitWarnings] attribute on method')] + public function test_parses_IgnorePhpunitWarnings_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(IgnorePhpunitWarningsTest::class, 'testOne')->isIgnorePhpunitWarnings(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isIgnorePhpunitWarnings()); + } + + #[TestDox('Parses #[PostCondition] attribute on method')] + public function test_parses_PostCondition_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'postCondition')->isPostCondition(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isPostCondition()); + } + + #[TestDox('Parses #[PreCondition] attribute on method')] + public function test_parses_PreCondition_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'preCondition')->isPreCondition(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isPreCondition()); + } + + #[TestDox('Parses #[PreserveGlobalState] attribute on method')] + public function test_parses_PreserveGlobalState_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(PreserveGlobalStateTest::class, 'testOne')->isPreserveGlobalState(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isPreserveGlobalState()); + $this->assertFalse($metadata->asArray()[0]->enabled()); + } + + #[TestDox('Parses #[RequiresMethod] attribute on method')] + public function test_parses_RequiresMethod_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresMethodTest::class, 'testOne')->isRequiresMethod(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresMethod()); + $this->assertSame('AnotherClassName', $metadata->asArray()[0]->className()); + $this->assertSame('anotherMethodName', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[RequiresFunction] attribute on method')] + public function test_parses_RequiresFunction_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresFunctionTest::class, 'testOne')->isRequiresFunction(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresFunction()); + $this->assertSame('g', $metadata->asArray()[0]->functionName()); + } + + #[TestDox('Parses #[RequiresOperatingSystem] attribute on method')] + public function test_parses_RequiresOperatingSystem_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresOperatingSystemTest::class, 'testOne')->isRequiresOperatingSystem(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresOperatingSystem()); + $this->assertSame('Linux', $metadata->asArray()[0]->operatingSystem()); + } + + #[TestDox('Parses #[RequiresOperatingSystemFamily] attribute on method')] + public function test_parses_RequiresOperatingSystemFamily_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresOperatingSystemFamilyTest::class, 'testOne')->isRequiresOperatingSystemFamily(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRequiresOperatingSystemFamily()); + $this->assertSame('Linux', $metadata->asArray()[0]->operatingSystemFamily()); + } + + #[TestDox('Parses #[RequiresPhp] attribute on method')] + public function test_parses_RequiresPhp_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresPhpTest::class, 'testOne')->isRequiresPhp(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhp()); + + assert($requirement instanceof RequiresPhp); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ConstraintRequirement); + + $this->assertSame('^8.0', $versionRequirement->asString()); + } + + #[TestDox('Parses #[RequiresPhpExtension] attribute on method')] + public function test_parses_RequiresPhpExtension_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresPhpExtensionTest::class, 'testOne')->isRequiresPhpExtension(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhpExtension()); + + assert($requirement instanceof RequiresPhpExtension); + + $this->assertSame('bar', $requirement->extension()); + $this->assertTrue($requirement->hasVersionRequirement()); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ComparisonRequirement); + + $this->assertSame('>= 2.0', $versionRequirement->asString()); + + $metadata = $this->parser()->forMethod(RequiresPhpExtensionTest::class, 'testTwo'); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhpExtension()); + + assert($requirement instanceof RequiresPhpExtension); + + $this->assertSame('baz', $requirement->extension()); + $this->assertTrue($requirement->hasVersionRequirement()); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ConstraintRequirement); + + $this->assertSame('^1.0', $versionRequirement->asString()); + } + + #[TestDox('Parses #[RequiresPhpunit] attribute on method')] + public function test_parses_RequiresPhpunit_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresPhpunitTest::class, 'testOne')->isRequiresPhpunit(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresPhpunit()); + + assert($requirement instanceof RequiresPhpunit); + + $versionRequirement = $requirement->versionRequirement(); + + assert($versionRequirement instanceof ConstraintRequirement); + + $this->assertSame('^10.0', $versionRequirement->asString()); + } + + #[TestDox('Parses #[RequiresPhpunitExtension] attribute on method')] + public function test_parses_RequiresPhpunitExtension_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresPhpunitExtensionTest::class, 'testOne')->isRequiresPhpunitExtension(); + + $this->assertCount(2, $metadata); + + $requirement = $metadata->asArray()[0]; + $this->assertTrue($requirement->isRequiresPhpunitExtension()); + assert($requirement instanceof RequiresPhpunitExtension); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\SomeExtension', $requirement->extensionClass()); + + $requirement = $metadata->asArray()[1]; + $this->assertTrue($requirement->isRequiresPhpunitExtension()); + assert($requirement instanceof RequiresPhpunitExtension); + $this->assertSame('PHPUnit\TestFixture\Metadata\Attribute\SomeOtherExtension', $requirement->extensionClass()); + } + + #[TestDox('Parses #[RequiresEnvironmentVariable] attribute on method')] + public function test_parses_RequiresEnvironmentVariable_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresEnvironmentVariableTest::class, 'testOne')->isRequiresEnvironmentVariable(); + + $this->assertCount(2, $metadata); + + $requirement = $metadata->asArray()[0]; + $this->assertTrue($requirement->isRequiresEnvironmentVariable()); + assert($requirement instanceof RequiresEnvironmentVariable); + $this->assertSame('foo', $requirement->environmentVariableName()); + $this->assertNull($requirement->value()); + + $requirement = $metadata->asArray()[1]; + $this->assertTrue($requirement->isRequiresEnvironmentVariable()); + assert($requirement instanceof RequiresEnvironmentVariable); + $this->assertSame('bar', $requirement->environmentVariableName()); + $this->assertSame('baz', $requirement->value()); + } + + #[TestDox('Parses #[WithEnvironmentVariable] attribute on method')] + public function test_parses_WithEnvironmentVariable_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(WithEnvironmentVariableTest::class, 'testOne')->isWithEnvironmentVariable(); + + $this->assertCount(2, $metadata); + + $withEnvironmentVariable = $metadata->asArray()[0]; + $this->assertTrue($withEnvironmentVariable->isWithEnvironmentVariable()); + assert($withEnvironmentVariable instanceof WithEnvironmentVariable); + $this->assertSame('foo', $withEnvironmentVariable->environmentVariableName()); + $this->assertNull($withEnvironmentVariable->value()); + + $withEnvironmentVariable = $metadata->asArray()[1]; + $this->assertTrue($withEnvironmentVariable->isWithEnvironmentVariable()); + assert($withEnvironmentVariable instanceof WithEnvironmentVariable); + $this->assertSame('bar', $withEnvironmentVariable->environmentVariableName()); + $this->assertSame('baz', $withEnvironmentVariable->value()); + } + + #[TestDox('Parses #[RequiresSetting] attribute on method')] + public function test_parses_RequiresSetting_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(RequiresSettingTest::class, 'testOne')->isRequiresSetting(); + + $this->assertCount(1, $metadata); + + $requirement = $metadata->asArray()[0]; + + $this->assertTrue($requirement->isRequiresSetting()); + + assert($requirement instanceof RequiresSetting); + + $this->assertSame('another-setting', $requirement->setting()); + $this->assertSame('another-value', $requirement->value()); + } + + #[TestDox('Parses #[RunInSeparateProcess] attribute on method')] + public function test_parses_RunInSeparateProcess_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(ProcessIsolationTest::class, 'testOne')->isRunInSeparateProcess(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isRunInSeparateProcess()); + } + + #[TestDox('Parses #[Test] attribute on method')] + public function test_parses_Test_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(SmallTest::class, 'one')->isTest(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTest()); + } + + #[TestDox('Parses #[TestDox] attribute on method')] + public function test_parses_TestDox_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(TestDoxTest::class, 'testOne')->isTestDox(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestDox()); + $this->assertSame('text', $metadata->asArray()[0]->text()); + } + + #[TestDox('Parses #[TestDoxFormatter] attribute on method')] + public function test_parses_TestDoxFormatter_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(TestDoxTest::class, 'testTwo')->isTestDoxFormatter(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestDoxFormatter()); + $this->assertSame('methodName', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[TestDoxFormatterExternal] attribute on method')] + public function test_parses_TestDoxFormatterExternal_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(TestDoxTest::class, 'testThree')->isTestDoxFormatter(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestDoxFormatter()); + $this->assertSame('ClassName', $metadata->asArray()[0]->className()); + $this->assertSame('methodName', $metadata->asArray()[0]->methodName()); + } + + #[TestDox('Parses #[TestWith] attribute on method')] + public function test_parses_TestWith_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(TestWithTest::class, 'testOne')->isTestWith(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestWith()); + $this->assertSame([1, 2, 3], $metadata->asArray()[0]->data()); + $this->assertFalse($metadata->asArray()[0]->hasName()); + $this->assertNull($metadata->asArray()[0]->name()); + } + + #[TestDox('Parses #[TestWith] attribute with name on method')] + public function test_parses_TestWith_attribute_with_name_on_method(): void + { + $metadata = $this->parser()->forMethod(TestWithTest::class, 'testOneWithName')->isTestWith(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestWith()); + $this->assertSame([1, 2, 3], $metadata->asArray()[0]->data()); + $this->assertTrue($metadata->asArray()[0]->hasName()); + $this->assertSame('Name1', $metadata->asArray()[0]->name()); + } + + #[TestDox('Parses #[TestWithJson] attribute on method')] + public function test_parses_TestWithJson_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(TestWithTest::class, 'testTwo')->isTestWith(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestWith()); + $this->assertSame([1, 2, 3], $metadata->asArray()[0]->data()); + $this->assertFalse($metadata->asArray()[0]->hasName()); + $this->assertNull($metadata->asArray()[0]->name()); + } + + #[TestDox('Parses #[TestWithJson] attribute with name on method')] + public function test_parses_TestWithJson_attribute_with_name_on_method(): void + { + $metadata = $this->parser()->forMethod(TestWithTest::class, 'testTwoWithName')->isTestWith(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isTestWith()); + $this->assertSame([1, 2, 3], $metadata->asArray()[0]->data()); + $this->assertTrue($metadata->asArray()[0]->hasName()); + $this->assertSame('Name2', $metadata->asArray()[0]->name()); + } + + #[TestDox('Parses #[Ticket] attribute on method')] + public function test_parses_Ticket_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(GroupTest::class, 'testOne')->isGroup(); + + $this->assertCount(2, $metadata); + $this->assertTrue($metadata->asArray()[1]->isGroup()); + $this->assertSame('another-ticket', $metadata->asArray()[1]->groupName()); + } + + #[TestDox('Parses #[WithoutErrorHandler] attribute on method')] + public function test_parses_WithoutErrorHandler_attribute_on_method(): void + { + $metadata = $this->parser()->forMethod(WithoutErrorHandlerTest::class, 'testOne')->isWithoutErrorHandler(); + + $this->assertCount(1, $metadata); + $this->assertTrue($metadata->asArray()[0]->isWithoutErrorHandler()); + } + + public function test_parses_attributes_for_class_and_method(): void + { + $metadata = $this->parser()->forClassAndMethod(CoversTest::class, 'testOne'); + + $this->assertCount(1, $metadata->isCoversClass()); + $this->assertCount(1, $metadata->isCoversFunction()); + } + + public function test_ignores_attributes_not_owned_by_PHPUnit(): void + { + $metadata = $this->parser()->forClassAndMethod(NonPhpunitAttributeTest::class, 'testOne'); + + $this->assertTrue($metadata->isEmpty()); + } + + public function test_ignores_attributes_in_PHPUnit_namespace_that_do_not_exist(): void + { + $metadata = $this->parser()->forClassAndMethod(PhpunitAttributeThatDoesNotExistTest::class, 'testOne'); + + $this->assertTrue($metadata->isEmpty()); + } + + public function test_handles_ReflectionException_raised_when_instantiating_attribute_on_class(): void + { + $this->expectException(InvalidAttributeException::class); + + $this->parser()->forClass(DuplicateSmallAttributeTest::class); + } + + public function test_handles_ReflectionException_raised_when_instantiating_attribute_on_method(): void + { + $this->expectException(InvalidAttributeException::class); + + $this->parser()->forMethod(DuplicateTestAttributeTest::class, 'testOne'); + } + + abstract protected function parser(): Parser; +} diff --git a/tests/unit/Metadata/Parser/CachedAttributeParserTest.php b/tests/unit/Metadata/Parser/CachedAttributeParserTest.php new file mode 100644 index 00000000000..ccfd66d5e66 --- /dev/null +++ b/tests/unit/Metadata/Parser/CachedAttributeParserTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata\Parser; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(CachingParser::class)] +#[Small] +#[Group('metadata')] +#[Group('metadata/attributes')] +final class CachedAttributeParserTest extends AttributeParserTestCase +{ + protected function parser(): Parser + { + return new CachingParser(new AttributeParser); + } +} diff --git a/tests/unit/Metadata/Version/RequirementTest.php b/tests/unit/Metadata/Version/RequirementTest.php new file mode 100644 index 00000000000..a1b0a8f02a5 --- /dev/null +++ b/tests/unit/Metadata/Version/RequirementTest.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Metadata; + +use PharIo\Version\VersionConstraintParser; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Group; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\Version\ComparisonRequirement; +use PHPUnit\Metadata\Version\ConstraintRequirement; +use PHPUnit\Metadata\Version\Requirement; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(ComparisonRequirement::class)] +#[CoversClass(ConstraintRequirement::class)] +#[CoversClass(Requirement::class)] +#[UsesClass(VersionComparisonOperator::class)] +#[Small] +#[Group('metadata')] +final class RequirementTest extends TestCase +{ + public static function constraintProvider(): array + { + return [ + [ + true, + '1.0.0', + new ConstraintRequirement( + (new VersionConstraintParser)->parse('1.0.0'), + ), + ], + ]; + } + + public static function comparisonProvider(): array + { + return [ + [true, '1.0.0', new ComparisonRequirement('1.0.0', new VersionComparisonOperator('='))], + ]; + } + + public function testCanBeCreatedFromStringWithVersionConstraint(): void + { + $requirement = Requirement::from('^1.0'); + + $this->assertInstanceOf(ConstraintRequirement::class, $requirement); + $this->assertSame('^1.0', $requirement->asString()); + } + + #[DataProvider('constraintProvider')] + public function testVersionRequirementCanBeCheckedUsingVersionConstraint(bool $expected, string $version, ConstraintRequirement $requirement): void + { + $this->assertSame($expected, $requirement->isSatisfiedBy($version)); + } + + public function testCanBeCreatedFromStringWithSimpleComparison(): void + { + $requirement = Requirement::from('>= 1.0'); + + $this->assertInstanceOf(ComparisonRequirement::class, $requirement); + $this->assertSame('>= 1.0', $requirement->asString()); + } + + #[DataProvider('comparisonProvider')] + public function testVersionRequirementCanBeCheckedUsingSimpleComparison(bool $expected, string $version, ComparisonRequirement $requirement): void + { + $this->assertSame($expected, $requirement->isSatisfiedBy($version)); + } + + public function testCannotBeCreatedFromInvalidString(): void + { + $this->expectException(InvalidVersionRequirementException::class); + + Requirement::from('invalid'); + } +} diff --git a/tests/unit/Runner/Baseline/BaselineTest.php b/tests/unit/Runner/Baseline/BaselineTest.php new file mode 100644 index 00000000000..a93cf49c883 --- /dev/null +++ b/tests/unit/Runner/Baseline/BaselineTest.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function realpath; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Baseline::class)] +#[Small] +final class BaselineTest extends TestCase +{ + public function testGroupsIssuesByFileAndLine(): void + { + $baseline = new Baseline; + + $baseline->add($this->issue()); + + $issues = $baseline->groupedByFileAndLine(); + + $this->assertCount(1, $issues); + $this->assertArrayHasKey($this->issue()->file(), $issues); + + $lines = $issues[$this->issue()->file()]; + + $this->assertCount(1, $lines); + $this->assertArrayHasKey(10, $lines); + + $line = $lines[10]; + + $this->assertCount(1, $line); + $this->assertArrayHasKey(0, $line); + + $this->assertTrue($this->issue()->equals($line[0])); + } + + public function testCanBeQueried(): void + { + $baseline = new Baseline; + + $baseline->add($this->issue()); + + $this->assertTrue($baseline->has($this->issue())); + $this->assertFalse($baseline->has($this->anotherIssue())); + $this->assertFalse($baseline->has($this->yetAnotherIssue())); + } + + private function issue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'Undefined variable $b', + ); + } + + private function anotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 11, + null, + 'Undefined variable $c', + ); + } + + private function yetAnotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'yet another issue', + ); + } +} diff --git a/tests/unit/Runner/Baseline/IssueTest.php b/tests/unit/Runner/Baseline/IssueTest.php new file mode 100644 index 00000000000..b484f3c93f4 --- /dev/null +++ b/tests/unit/Runner/Baseline/IssueTest.php @@ -0,0 +1,96 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function realpath; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\FileDoesNotExistException; + +#[CoversClass(Issue::class)] +#[CoversClass(FileDoesNotExistException::class)] +#[CoversClass(FileDoesNotHaveLineException::class)] +#[Small] +final class IssueTest extends TestCase +{ + public function testHasFile(): void + { + $this->assertSame( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + $this->issue()->file(), + ); + } + + public function testHasLine(): void + { + $this->assertSame(10, $this->issue()->line()); + } + + public function testHasHash(): void + { + $this->assertSame('6bf70f0b8c461415955e2d3a97cfbe664f5b957b', $this->issue()->hash()); + } + + public function testHasDescription(): void + { + $this->assertSame('Undefined variable $b', $this->issue()->description()); + } + + public function testIsComparable(): void + { + $this->assertTrue($this->issue()->equals($this->issue())); + $this->assertFalse($this->issue()->equals($this->anotherIssue())); + } + + public function testCannotBeCreatedForFileThatDoesNotExist(): void + { + $this->expectException(FileDoesNotExistException::class); + + Issue::from( + 'does-not-exist.php', + 1, + null, + 'description', + ); + } + + public function testCannotBeCreatedForLineThatDoesNotExist(): void + { + $this->expectException(FileDoesNotHaveLineException::class); + + Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 1234, + null, + 'description', + ); + } + + private function issue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'Undefined variable $b', + ); + } + + private function anotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 11, + null, + 'Undefined variable $c', + ); + } +} diff --git a/tests/unit/Runner/Baseline/ReaderTest.php b/tests/unit/Runner/Baseline/ReaderTest.php new file mode 100644 index 00000000000..0f95fedda48 --- /dev/null +++ b/tests/unit/Runner/Baseline/ReaderTest.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use function realpath; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Reader::class)] +#[Small] +final class ReaderTest extends TestCase +{ + public function testReadsBaselineFromFileWithValidXml(): void + { + $baseline = (new Reader)->read(__DIR__ . '/../../../_files/baseline/expected.xml'); + + $this->assertTrue($baseline->has($this->issue())); + $this->assertTrue($baseline->has($this->anotherIssue())); + $this->assertTrue($baseline->has($this->yetAnotherIssue())); + } + + public function testCannotReadBaselineFromFileThatDoesNotExist(): void + { + $this->expectException(CannotLoadBaselineException::class); + + (new Reader)->read('does-not-exist.xml'); + } + + public function testCannotReadBaselineFromFileWithInvalidXml(): void + { + $this->expectException(CannotLoadBaselineException::class); + + (new Reader)->read(realpath(__DIR__ . '/../../../end-to-end/_files/baseline/invalid-baseline/baseline.xml')); + } + + public function testCannotReadBaselineFromFileWithIncompatibleXml(): void + { + $this->expectException(CannotLoadBaselineException::class); + + (new Reader)->read(realpath(__DIR__ . '/../../../end-to-end/_files/baseline/unsupported-baseline/baseline.xml')); + } + + private function issue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'Undefined variable $b', + ); + } + + private function anotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 11, + null, + 'Undefined variable $c', + ); + } + + private function yetAnotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'yet another issue', + ); + } +} diff --git a/tests/unit/Runner/Baseline/RelativePathCalculatorTest.php b/tests/unit/Runner/Baseline/RelativePathCalculatorTest.php new file mode 100644 index 00000000000..7ca8ac54dc1 --- /dev/null +++ b/tests/unit/Runner/Baseline/RelativePathCalculatorTest.php @@ -0,0 +1,135 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(RelativePathCalculator::class)] +#[Small] +/** + * @see Copied from https://github.com/phpstan/phpstan-src/blob/1.10.33/src/File/ParentDirectoryRelativePathHelper.php + */ +final class RelativePathCalculatorTest extends TestCase +{ + public static function dataGetRelativePath(): array + { + return [ + [ + '/usr/var/www', + '/usr/var/www/test.php', + 'test.php', + ], + [ + '/usr/var/www/foo/bar/baz', + '/usr/var/www/test.php', + '../../../test.php', + ], + [ + '/', + '/usr/var/www/test.php', + '/usr/var/www/test.php', + ], + [ + '/usr/var/www', + '/usr/var/www/src/test.php', + 'src/test.php', + ], + [ + '/usr/var/www/', + '/usr/var/www/src/test.php', + 'src/test.php', + ], + [ + '/usr/var/www', + '/usr/var/test.php', + '../test.php', + ], + [ + '/usr/var/www/', + '/usr/var/test.php', + '../test.php', + ], + [ + '/usr/var/www/', + '/usr/var/web/test.php', + '../web/test.php', + ], + [ + '/usr/var/www/', + '/usr/var/web/foo/test.php', + '../web/foo/test.php', + ], + [ + '/', + '/test.php', + '/test.php', + ], + [ + '/var/www', + '/usr/test.php', + '/usr/test.php', + ], + [ + 'C:\\var', + 'C:\\var\\test.php', + 'test.php', + ], + [ + 'C:\\var', + 'C:\\var\\src\\test.php', + 'src/test.php', + ], + [ + 'C:\\var', + 'C:\\test.php', + '../test.php', + ], + [ + 'C:\\var\\', + 'C:\\usr\\test.php', + '../usr/test.php', + ], + [ + 'C:\\', + 'C:\\test.php', + 'test.php', + ], + [ + 'C:\\', + 'C:\\src\\test.php', + 'src/test.php', + ], + [ + 'C:\\var', + 'D:\\var\\src\\test.php', + 'D:\\var\\src\\test.php', + ], + [ + '/usr/var/www', + 'file:///usr/var/www/test.php', + 'test.php', + ], + ]; + } + + #[DataProvider('dataGetRelativePath')] + public function testGetRelativePath(string $baselineDirectory, string $filename, string $expectedRelativePath): void + { + $calculator = new RelativePathCalculator($baselineDirectory); + + $this->assertSame( + $expectedRelativePath, + $calculator->calculate($filename), + ); + } +} diff --git a/tests/unit/Runner/Baseline/WriterTest.php b/tests/unit/Runner/Baseline/WriterTest.php new file mode 100644 index 00000000000..29bed42389a --- /dev/null +++ b/tests/unit/Runner/Baseline/WriterTest.php @@ -0,0 +1,103 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Baseline; + +use const DIRECTORY_SEPARATOR; +use function getcwd; +use function ltrim; +use function realpath; +use function str_replace; +use function unlink; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Writer::class)] +#[Small] +final class WriterTest extends TestCase +{ + private string $target; + + public static function baselinePathProvider(): iterable + { + $absoluteBaselinePath = __DIR__ . '/../../../_files/baseline/expected.xml'; + + yield [$absoluteBaselinePath]; + + yield [ltrim(str_replace(getcwd(), '', $absoluteBaselinePath), DIRECTORY_SEPARATOR)]; + } + + protected function setUp(): void + { + $this->target = realpath(__DIR__ . '/../../../_files/baseline') . DIRECTORY_SEPARATOR . 'actual.xml'; + } + + protected function tearDown(): void + { + @unlink($this->target); + } + + #[DataProvider('baselinePathProvider')] + public function testWritesBaselineToFileInXmlFormat(string $baselinePath): void + { + (new Writer)->write($this->target, $this->baseline()); + + $this->assertXmlFileEqualsXmlFile($baselinePath, $this->target); + } + + public function testItThrowsExceptionIfBaseLinePathDoesNotExists(): void + { + $this->expectException(CannotWriteBaselineException::class); + + (new Writer)->write('/path/to/invalid', $this->baseline()); + } + + private function baseline(): Baseline + { + $baseline = new Baseline; + + $baseline->add($this->issue()); + $baseline->add($this->anotherIssue()); + $baseline->add($this->yetAnotherIssue()); + + return $baseline; + } + + private function issue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'Undefined variable $b', + ); + } + + private function anotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 11, + null, + 'Undefined variable $c', + ); + } + + private function yetAnotherIssue(): Issue + { + return Issue::from( + realpath(__DIR__ . '/../../../_files/baseline/FileWithIssues.php'), + 10, + null, + 'yet another issue', + ); + } +} diff --git a/tests/unit/Runner/ErrorHandlerTest.php b/tests/unit/Runner/ErrorHandlerTest.php new file mode 100644 index 00000000000..5dd9c63137a --- /dev/null +++ b/tests/unit/Runner/ErrorHandlerTest.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use const E_USER_DEPRECATED; +use function trigger_error; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use ReflectionClass; + +#[CoversClass(ErrorHandler::class)] +#[Small] +final class ErrorHandlerTest extends TestCase +{ + public function testThrowsExceptionWhenUsingInvalidOrderOption(): void + { + $errorHandler = ErrorHandler::instance(); + $errorHandler->registerDeprecationHandler(); + trigger_error('deprecation', E_USER_DEPRECATED); + $errorHandler->restoreDeprecationHandler(); + $refl = new ReflectionClass($errorHandler); + $globalDeprecations = $refl->getProperty('globalDeprecations'); + $registeredDeprecations = $globalDeprecations->getValue($errorHandler); + $this->assertCount(1, $registeredDeprecations); + $this->assertSame('deprecation', $registeredDeprecations[0][1]); + $globalDeprecations->setValue($errorHandler, []); + } +} diff --git a/tests/unit/Runner/Filter/ExcludeNameFilterIteratorTest.php b/tests/unit/Runner/Filter/ExcludeNameFilterIteratorTest.php new file mode 100644 index 00000000000..83a77d6c392 --- /dev/null +++ b/tests/unit/Runner/Filter/ExcludeNameFilterIteratorTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\TestFixture\BankAccountTest; + +#[CoversClass(ExcludeNameFilterIterator::class)] +#[Small] +class ExcludeNameFilterIteratorTest extends TestCase +{ + /** + * @throws Exception + */ + public function testCaseSensitiveMatch(): void + { + $this->assertTrue($this->createFilter('NotMatchingPattern')->accept()); + } + + /** + * @throws Exception + */ + public function testCaseInsensitiveMatch(): void + { + $this->assertTrue($this->createFilter('notmatchingbankaccount')->accept()); + } + + /** + * @throws Exception + */ + private function createFilter(string $filter): ExcludeNameFilterIterator + { + $suite = TestSuite::empty('test suite name'); + $suite->addTest(new BankAccountTest('testBalanceIsInitiallyZero')); + + $iterator = new ExcludeNameFilterIterator($suite->getIterator(), $filter); + + $iterator->rewind(); + + return $iterator; + } +} diff --git a/tests/unit/Runner/Filter/IncludeNameFilterIteratorTest.php b/tests/unit/Runner/Filter/IncludeNameFilterIteratorTest.php new file mode 100644 index 00000000000..7ce439efd06 --- /dev/null +++ b/tests/unit/Runner/Filter/IncludeNameFilterIteratorTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\TestFixture\BankAccountTest; + +#[CoversClass(IncludeNameFilterIterator::class)] +#[Small] +final class IncludeNameFilterIteratorTest extends TestCase +{ + /** + * @throws Exception + */ + public function testCaseSensitiveMatch(): void + { + $this->assertTrue($this->createFilter('BankAccountTest')->accept()); + } + + /** + * @throws Exception + */ + public function testCaseInsensitiveMatch(): void + { + $this->assertTrue($this->createFilter('bankaccounttest')->accept()); + } + + /** + * @throws Exception + */ + private function createFilter(string $filter): IncludeNameFilterIterator + { + $suite = TestSuite::empty('test suite name'); + $suite->addTest(new BankAccountTest('testBalanceIsInitiallyZero')); + + $iterator = new IncludeNameFilterIterator($suite->getIterator(), $filter); + + $iterator->rewind(); + + return $iterator; + } +} diff --git a/tests/unit/Runner/Filter/TestIdFilterIteratorTest.php b/tests/unit/Runner/Filter/TestIdFilterIteratorTest.php new file mode 100644 index 00000000000..dc448e16b56 --- /dev/null +++ b/tests/unit/Runner/Filter/TestIdFilterIteratorTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Filter; + +use function assert; +use Iterator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Framework\TestSuite; +use PHPUnit\Framework\TestSuiteIterator; +use PHPUnit\TestFixture\BankAccountTest; + +#[CoversClass(TestIdFilterIterator::class)] +#[CoversClass(TestSuiteIterator::class)] +#[Small] +final class TestIdFilterIteratorTest extends TestCase +{ + public function testAcceptsTestsBasedOnTheirId(): void + { + $id = 'PHPUnit\TestFixture\BankAccountTest::testBalanceCannotBecomeNegative'; + + foreach ($this->testSuiteIterator([$id]) as $test) { + assert($test instanceof TestCase); + + $this->assertSame($id, $test->valueObjectForEvents()->id()); + } + } + + /** + * @param list $testIds + */ + private function testSuiteIterator(array $testIds): Iterator + { + $factory = new Factory; + + $factory->addTestIdFilter($testIds); + + $testSuite = $this->testSuite(); + + $testSuite->injectFilter($factory); + + return $testSuite->getIterator(); + } + + private function testSuite(): TestSuite + { + $suite = TestSuite::empty('test suite name'); + + $suite->addTest(new BankAccountTest('testBalanceIsInitiallyZero')); + $suite->addTest(new BankAccountTest('testBalanceCannotBecomeNegative')); + $suite->addTest(new BankAccountTest('testBalanceCannotBecomeNegative2')); + + return $suite; + } +} diff --git a/tests/unit/Runner/HookMethod/HookMethodCollectionTest.php b/tests/unit/Runner/HookMethod/HookMethodCollectionTest.php new file mode 100644 index 00000000000..600bd95c4c7 --- /dev/null +++ b/tests/unit/Runner/HookMethod/HookMethodCollectionTest.php @@ -0,0 +1,72 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(HookMethodCollection::class)] +#[Small] +final class HookMethodCollectionTest extends TestCase +{ + public static function provider(): iterable + { + return [ + [ + HookMethodCollection::defaultBeforeClass()->add(new HookMethod('someMethod', 0)), + ['someMethod', 'setUpBeforeClass'], + ], + [ + HookMethodCollection::defaultBefore()->add(new HookMethod('someMethod', 0)), + ['someMethod', 'setUp'], + ], + [ + HookMethodCollection::defaultPreCondition()->add(new HookMethod('someMethod', 0)), + ['someMethod', 'assertPreConditions'], + ], + [ + HookMethodCollection::defaultPostCondition()->add(new HookMethod('someMethod', 0)), + ['assertPostConditions', 'someMethod'], + ], + [ + HookMethodCollection::defaultAfter()->add(new HookMethod('someMethod', 0)), + ['tearDown', 'someMethod'], + ], + [ + HookMethodCollection::defaultAfterClass()->add(new HookMethod('someMethod', 0)), + ['tearDownAfterClass', 'someMethod'], + ], + [ + HookMethodCollection::defaultBeforeClass() + ->add(new HookMethod('methodWithHighPriority', priority: 1)) + ->add(new HookMethod('methodWithVeryLowPriority', priority: -10)) + ->add(new HookMethod('methodWithLowPriority', priority: -1)) + ->add(new HookMethod('methodWithVeryHighPriority', priority: 10)) + ->add(new HookMethod('methodWithoutPriority', 0)), + [ + 'methodWithVeryHighPriority', + 'methodWithHighPriority', + 'methodWithoutPriority', + 'setUpBeforeClass', + 'methodWithLowPriority', + 'methodWithVeryLowPriority', + ], + ], + ]; + } + + #[DataProvider('provider')] + public function testIterator(HookMethodCollection $hookMethodsCollection, array $expected): void + { + $this->assertSame($expected, $hookMethodsCollection->methodNamesSortedByPriority()); + } +} diff --git a/tests/unit/Runner/Phpt/ParserTest.php b/tests/unit/Runner/Phpt/ParserTest.php new file mode 100644 index 00000000000..8abec6ddf28 --- /dev/null +++ b/tests/unit/Runner/Phpt/ParserTest.php @@ -0,0 +1,78 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\Phpt; + +use function glob; +use function str_replace; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Parser::class)] +#[Small] +final class ParserTest extends TestCase +{ + /** + * @return non-empty-array + */ + public static function unsupportedSections(): array + { + $data = []; + + foreach (glob(__DIR__ . '/../../../_files/phpt/unsupported/*.phpt') as $file) { + $data[str_replace([__DIR__ . '/../../../_files/phpt/unsupported/', '.phpt'], '', $file)] = [$file]; + } + + return $data; + } + + /** + * @return non-empty-list + */ + public static function invalidFiles(): array + { + $data = []; + + foreach (glob(__DIR__ . '/../../../_files/phpt/invalid/*.phpt') as $file) { + $data[] = [$file]; + } + + return $data; + } + + /** + * @param non-empty-string $file + */ + #[DataProvider('unsupportedSections')] + #[TestDox('PHPT section --$_dataName-- is not supported')] + public function testRejectsUnsupportedSections(string $file): void + { + $parser = new Parser; + + $this->expectException(UnsupportedPhptSectionException::class); + + $parser->parse($file); + } + + /** + * @param non-empty-string $file + */ + #[DataProvider('invalidFiles')] + public function testRejectsInvalidPhptFile(string $file): void + { + $parser = new Parser; + + $this->expectException(InvalidPhptFileException::class); + + $parser->parse($file); + } +} diff --git a/tests/unit/Runner/ResultCache/ResultCacheIdTest.php b/tests/unit/Runner/ResultCache/ResultCacheIdTest.php new file mode 100644 index 00000000000..4840973e2ab --- /dev/null +++ b/tests/unit/Runner/ResultCache/ResultCacheIdTest.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Runner\ResultCache; + +use PHPUnit\Event\Code\Phpt; +use PHPUnit\Event\Code\TestDox; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Reorderable; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\MetadataCollection; + +#[CoversClass(ResultCacheId::class)] +#[Small] +final class ResultCacheIdTest extends TestCase +{ + public static function provideResultCacheIds(): iterable + { + yield ['PHPUnit\Runner\ResultCache\ResultCacheIdTest::a method', ResultCacheId::fromTestClassAndMethodName(self::class, 'a method')]; + + yield ['PHPUnit\Runner\ResultCache\ResultCacheIdTest::testMethod', ResultCacheId::fromTest(self::testMethod())]; + } + + #[DataProvider('provideResultCacheIds')] + public function testResultCacheId(string $expectedString, ResultCacheId $cacheId): void + { + $this->assertSame($expectedString, $cacheId->asString()); + } + + public function testReorderableResultCacheId(): void + { + $reorderable = $this; + $this->assertInstanceOf(Reorderable::class, $reorderable); + + $this->assertSame('PHPUnit\Runner\ResultCache\ResultCacheIdTest::testReorderableResultCacheId', ResultCacheId::fromReorderable($reorderable)->asString()); + } + + public function testPhptResultCacheId(): void + { + $file = 'test.phpt'; + $phptTest = new Phpt($file); + + $this->assertSame('test.phpt', ResultCacheId::fromTest($phptTest)->asString()); + } + + private static function testMethod(): TestMethod + { + return new TestMethod( + self::class, + 'testMethod', + 'TestClass.php', + 1, + new TestDox('', '', ''), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } +} diff --git a/tests/unit/TextUI/AbstractSouceFilterTestCase.php b/tests/unit/TextUI/AbstractSouceFilterTestCase.php new file mode 100644 index 00000000000..accc20b1a64 --- /dev/null +++ b/tests/unit/TextUI/AbstractSouceFilterTestCase.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const DIRECTORY_SEPARATOR; +use function ltrim; +use function realpath; +use function str_replace; +use PHPUnit\Framework\TestCase; + +abstract class AbstractSouceFilterTestCase extends TestCase +{ + protected static function createSource( + ?FilterDirectoryCollection $includeDirectories = null, + ?FilterDirectoryCollection $excludeDirectories = null, + ?FileCollection $includeFiles = null, + ?FileCollection $excludeFiles = null, + ): Source { + return new Source( + null, + false, + $includeDirectories ?? FilterDirectoryCollection::fromArray([]), + $includeFiles ?? FileCollection::fromArray([]), + $excludeDirectories ?? FilterDirectoryCollection::fromArray([]), + $excludeFiles ?? FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + } + + protected static function fixturePath(?string $subPath = null): string + { + $path = realpath(__DIR__ . '/../..') . '/_files/source-filter'; + + if ($subPath !== null) { + $path = $path . '/' . ltrim($subPath, '/'); + } + + return str_replace('/', DIRECTORY_SEPARATOR, $path); + } +} diff --git a/tests/unit/TextUI/Command/Commands/AtLeastVersionCommandTest.php b/tests/unit/TextUI/Command/Commands/AtLeastVersionCommandTest.php new file mode 100644 index 00000000000..0d93287c93f --- /dev/null +++ b/tests/unit/TextUI/Command/Commands/AtLeastVersionCommandTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(AtLeastVersionCommand::class)] +#[Small] +final class AtLeastVersionCommandTest extends TestCase +{ + public function testSucceedsWhenRequirementIsMet(): void + { + $command = new AtLeastVersionCommand('10'); + + $result = $command->execute(); + + $this->assertSame('', $result->output()); + $this->assertSame(0, $result->shellExitCode()); + } + + public function testFailsWhenRequirementIsNotMet(): void + { + $command = new AtLeastVersionCommand('100'); + + $result = $command->execute(); + + $this->assertSame('', $result->output()); + $this->assertSame(1, $result->shellExitCode()); + } +} diff --git a/tests/unit/TextUI/Command/Commands/VersionCheckCommandTest.php b/tests/unit/TextUI/Command/Commands/VersionCheckCommandTest.php new file mode 100644 index 00000000000..7b3936a7b62 --- /dev/null +++ b/tests/unit/TextUI/Command/Commands/VersionCheckCommandTest.php @@ -0,0 +1,94 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Command; + +use const PHP_EOL; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\MockObject\Stub; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\Http\Downloader; + +#[CoversClass(VersionCheckCommand::class)] +#[Small] +final class VersionCheckCommandTest extends TestCase +{ + /** + * @return non-empty-list + */ + public static function provider(): array + { + return [ + [ + 'You are using the latest version of PHPUnit.' . PHP_EOL, + Result::SUCCESS, + 10, + '10.5.0', + '10.5.0', + '10.5.0', + ], + [ + 'You are not using the latest version of PHPUnit.' . PHP_EOL . + 'The latest version compatible with PHPUnit 10.5.0 is PHPUnit 10.5.1.' . PHP_EOL . + 'The latest version is PHPUnit 10.5.1.' . PHP_EOL, + Result::FAILURE, + 10, + '10.5.0', + '10.5.1', + '10.5.1', + ], + [ + 'You are not using the latest version of PHPUnit.' . PHP_EOL . + 'The latest version compatible with PHPUnit 10.5.0 is PHPUnit 10.5.1.' . PHP_EOL . + 'The latest version is PHPUnit 11.0.0.' . PHP_EOL, + Result::FAILURE, + 10, + '10.5.0', + '11.0.0', + '10.5.1', + ], + ]; + } + + /** + * @param non-empty-string $expectedMessage + * @param non-negative-int $expectedShellExitCode + * @param positive-int $majorVersionNumber + * @param non-empty-string $versionId + * @param non-empty-string $latestVersion + * @param non-empty-string $latestCompatibleVersion + */ + #[DataProvider('provider')] + public function testChecksVersion(string $expectedMessage, int $expectedShellExitCode, int $majorVersionNumber, string $versionId, string $latestVersion, string $latestCompatibleVersion): void + { + $command = new VersionCheckCommand( + $this->downloader($latestVersion, $latestCompatibleVersion), + $majorVersionNumber, + $versionId, + ); + + $result = $command->execute(); + + $this->assertSame($expectedMessage, $result->output()); + $this->assertSame($expectedShellExitCode, $result->shellExitCode()); + } + + private function downloader(string $latestVersion, string $latestCompatibleVersion): Downloader&Stub + { + $downloader = $this->createStub(Downloader::class); + + $downloader + ->method('download') + ->willReturn($latestVersion, $latestCompatibleVersion); + + return $downloader; + } +} diff --git a/tests/unit/TextUI/Configuration/Cli/BuilderTest.php b/tests/unit/TextUI/Configuration/Cli/BuilderTest.php new file mode 100644 index 00000000000..92fffb2062d --- /dev/null +++ b/tests/unit/TextUI/Configuration/Cli/BuilderTest.php @@ -0,0 +1,2713 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\CliArguments; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\TestSuiteSorter; + +#[CoversClass(Builder::class)] +#[CoversClass(Configuration::class)] +#[Small] +#[TestDox('CLI Options Parser')] +final class BuilderTest extends TestCase +{ + #[TestDox('argument')] + public function testArguments(): void + { + $configuration = (new Builder)->fromParameters(['command', 'argument']); + + $this->assertSame(['argument'], $configuration->arguments()); + } + + #[TestDox('--all')] + public function testAll(): void + { + $configuration = (new Builder)->fromParameters(['--all']); + + $this->assertTrue($configuration->hasAll()); + $this->assertTrue($configuration->all()); + } + + public function testAllMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasAll()); + + $this->expectException(Exception::class); + + $configuration->all(); + } + + #[TestDox('--colors')] + public function testColorsImplicitAuto(): void + { + $configuration = (new Builder)->fromParameters(['--colors']); + + $this->assertTrue($configuration->hasColors()); + $this->assertSame('auto', $configuration->colors()); + } + + #[TestDox('--colors=auto')] + public function testColorsExplicitAuto(): void + { + $configuration = (new Builder)->fromParameters(['--colors=auto']); + + $this->assertTrue($configuration->hasColors()); + $this->assertSame('auto', $configuration->colors()); + } + + #[TestDox('--colors=always')] + public function testColorsAlways(): void + { + $configuration = (new Builder)->fromParameters(['--colors=always']); + + $this->assertTrue($configuration->hasColors()); + $this->assertSame('always', $configuration->colors()); + } + + #[TestDox('--colors=never')] + public function testColorsNever(): void + { + $configuration = (new Builder)->fromParameters(['--colors=never']); + + $this->assertTrue($configuration->hasColors()); + $this->assertSame('never', $configuration->colors()); + } + + public function testColorsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasColors()); + + $this->expectException(Exception::class); + + $configuration->colors(); + } + + #[TestDox('--bootstrap script.php')] + public function testBootstrap(): void + { + $configuration = (new Builder)->fromParameters(['--bootstrap', 'script.php']); + + $this->assertTrue($configuration->hasBootstrap()); + $this->assertSame('script.php', $configuration->bootstrap()); + } + + public function testBootstrapMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasBootstrap()); + + $this->expectException(Exception::class); + + $configuration->bootstrap(); + } + + #[TestDox('--cache-directory directory')] + public function testCacheDirectory(): void + { + $configuration = (new Builder)->fromParameters(['--cache-directory', 'directory']); + + $this->assertTrue($configuration->hasCacheDirectory()); + $this->assertSame('directory', $configuration->cacheDirectory()); + } + + public function testCacheDirectoryMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCacheDirectory()); + + $this->expectException(Exception::class); + + $configuration->cacheDirectory(); + } + + #[TestDox('--cache-result')] + public function testCacheResult(): void + { + $configuration = (new Builder)->fromParameters(['--cache-result']); + + $this->assertTrue($configuration->hasCacheResult()); + $this->assertTrue($configuration->cacheResult()); + } + + #[TestDox('--do-not-cache-result')] + public function testDoNotCacheResult(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-cache-result']); + + $this->assertTrue($configuration->hasCacheResult()); + $this->assertFalse($configuration->cacheResult()); + } + + public function testCacheResultMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCacheResult()); + + $this->expectException(Exception::class); + + $configuration->cacheResult(); + } + + #[TestDox('--columns ')] + public function testColumnsNumber(): void + { + $configuration = (new Builder)->fromParameters(['--columns', '100']); + + $this->assertTrue($configuration->hasColumns()); + $this->assertSame(100, $configuration->columns()); + } + + #[TestDox('--columns max')] + public function testColumnsMax(): void + { + $configuration = (new Builder)->fromParameters(['--columns', 'max']); + + $this->assertTrue($configuration->hasColumns()); + $this->assertSame('max', $configuration->columns()); + } + + public function testColumnsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasColumns()); + + $this->expectException(Exception::class); + + $configuration->columns(); + } + + #[TestDox('-c file')] + public function testConfigurationShort(): void + { + $configuration = (new Builder)->fromParameters(['-c', 'file']); + + $this->assertTrue($configuration->hasConfigurationFile()); + $this->assertSame('file', $configuration->configurationFile()); + } + + #[TestDox('--configuration file')] + public function testConfiguration(): void + { + $configuration = (new Builder)->fromParameters(['--configuration', 'file']); + + $this->assertTrue($configuration->hasConfigurationFile()); + $this->assertSame('file', $configuration->configurationFile()); + } + + public function testConfigurationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasConfigurationFile()); + + $this->expectException(Exception::class); + + $configuration->configurationFile(); + } + + #[TestDox('--warm-coverage-cache')] + public function testWarmCoverageCache(): void + { + $configuration = (new Builder)->fromParameters(['--warm-coverage-cache']); + + $this->assertTrue($configuration->warmCoverageCache()); + } + + public function testWarmCoverageCacheMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->warmCoverageCache()); + } + + #[TestDox('--coverage-clover file')] + public function testCoverageClover(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-clover', 'file']); + + $this->assertTrue($configuration->hasCoverageClover()); + $this->assertSame('file', $configuration->coverageClover()); + } + + public function testCoverageCloverMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageClover()); + + $this->expectException(Exception::class); + + $configuration->coverageClover(); + } + + #[TestDox('--coverage-cobertura file')] + public function testCoverageCobertura(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-cobertura', 'file']); + + $this->assertTrue($configuration->hasCoverageCobertura()); + $this->assertSame('file', $configuration->coverageCobertura()); + } + + public function testCoverageCoberturaMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageCobertura()); + + $this->expectException(Exception::class); + + $configuration->coverageCobertura(); + } + + #[TestDox('--coverage-crap4j file')] + public function testCoverageCrap4j(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-crap4j', 'file']); + + $this->assertTrue($configuration->hasCoverageCrap4J()); + $this->assertSame('file', $configuration->coverageCrap4J()); + } + + public function testCoverageCrap4jMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageCrap4J()); + + $this->expectException(Exception::class); + + $configuration->coverageCrap4J(); + } + + #[TestDox('--coverage-html directory')] + public function testCoverageHtml(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-html', 'directory']); + + $this->assertTrue($configuration->hasCoverageHtml()); + $this->assertSame('directory', $configuration->coverageHtml()); + } + + public function testCoverageHtmlMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageHtml()); + + $this->expectException(Exception::class); + + $configuration->coverageHtml(); + } + + #[TestDox('--coverage-openclover file')] + public function testCoverageOpenClover(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-openclover', 'file']); + + $this->assertTrue($configuration->hasCoverageOpenClover()); + $this->assertSame('file', $configuration->coverageOpenClover()); + } + + public function testCoverageOpenCloverMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageOpenClover()); + + $this->expectException(Exception::class); + + $configuration->coverageOpenClover(); + } + + #[TestDox('--coverage-php file')] + public function testCoveragePhp(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-php', 'file']); + + $this->assertTrue($configuration->hasCoveragePhp()); + $this->assertSame('file', $configuration->coveragePhp()); + } + + public function testCoveragePhpMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoveragePhp()); + + $this->expectException(Exception::class); + + $configuration->coveragePhp(); + } + + #[TestDox('--coverage-text')] + public function testCoverageText(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-text']); + + $this->assertTrue($configuration->hasCoverageText()); + $this->assertSame('php://stdout', $configuration->coverageText()); + } + + #[TestDox('--coverage-text=file')] + public function testCoverageTextFile(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-text=file']); + + $this->assertTrue($configuration->hasCoverageText()); + $this->assertSame('file', $configuration->coverageText()); + } + + public function testCoverageTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageText()); + + $this->expectException(Exception::class); + + $configuration->coverageText(); + } + + #[TestDox('--only-summary-for-coverage-text')] + public function testOnlySummaryForCoverageText(): void + { + $configuration = (new Builder)->fromParameters(['--only-summary-for-coverage-text']); + + $this->assertTrue($configuration->hasCoverageTextShowOnlySummary()); + $this->assertTrue($configuration->coverageTextShowOnlySummary()); + } + + public function testOnlySummaryForCoverageTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageTextShowOnlySummary()); + + $this->expectException(Exception::class); + + $configuration->coverageTextShowOnlySummary(); + } + + #[TestDox('--show-uncovered-for-coverage-text')] + public function testShowUncoveredForCoverageText(): void + { + $configuration = (new Builder)->fromParameters(['--show-uncovered-for-coverage-text']); + + $this->assertTrue($configuration->hasCoverageTextShowUncoveredFiles()); + $this->assertTrue($configuration->coverageTextShowUncoveredFiles()); + } + + public function testShowUncoveredForCoverageTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageTextShowUncoveredFiles()); + + $this->expectException(Exception::class); + + $configuration->coverageTextShowUncoveredFiles(); + } + + #[TestDox('--coverage-xml directory')] + public function testCoverageXml(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-xml', 'directory']); + + $this->assertTrue($configuration->hasCoverageXml()); + $this->assertSame('directory', $configuration->coverageXml()); + } + + public function testCoverageXmlMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageXml()); + + $this->expectException(Exception::class); + + $configuration->coverageXml(); + } + + #[TestDox('--exclude-source-from-xml-coverage=')] + public function testExcludeSourceFromXmlCoverage(): void + { + $configuration = (new Builder)->fromParameters(['--exclude-source-from-xml-coverage']); + + $this->assertTrue($configuration->hasExcludeSourceFromXmlCoverage()); + $this->assertTrue($configuration->excludeSourceFromXmlCoverage()); + } + + public function testExcludeSourceFromXmlCoverageMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExcludeSourceFromXmlCoverage()); + + $this->expectException(Exception::class); + + $configuration->excludeSourceFromXmlCoverage(); + } + + #[TestDox('--path-coverage')] + public function testPathCoverage(): void + { + $configuration = (new Builder)->fromParameters(['--path-coverage']); + + $this->assertTrue($configuration->hasPathCoverage()); + $this->assertTrue($configuration->pathCoverage()); + } + + public function testPathCoverageMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasPathCoverage()); + + $this->expectException(Exception::class); + + $configuration->pathCoverage(); + } + + #[TestDox('-d foo=bar')] + public function testIniSetting(): void + { + $configuration = (new Builder)->fromParameters(['-d', 'foo=bar']); + + $this->assertTrue($configuration->hasIniSettings()); + $this->assertSame(['foo' => 'bar'], $configuration->iniSettings()); + } + + #[TestDox('-d foo')] + public function testIniSetting2(): void + { + $configuration = (new Builder)->fromParameters(['-d', 'foo']); + + $this->assertTrue($configuration->hasIniSettings()); + $this->assertSame(['foo' => '1'], $configuration->iniSettings()); + } + + public function testIniSettingMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasIniSettings()); + + $this->expectException(Exception::class); + + $configuration->iniSettings(); + } + + #[TestDox('-h')] + public function testHelpShort(): void + { + $configuration = (new Builder)->fromParameters(['-h']); + + $this->assertTrue($configuration->help()); + } + + #[TestDox('--help')] + public function testHelp(): void + { + $configuration = (new Builder)->fromParameters(['--help']); + + $this->assertTrue($configuration->help()); + } + + public function testHelpMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->help()); + } + + #[TestDox('--filter string')] + public function testFilter(): void + { + $configuration = (new Builder)->fromParameters(['--filter', 'string']); + + $this->assertTrue($configuration->hasFilter()); + $this->assertSame('string', $configuration->filter()); + } + + public function testFilterMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFilter()); + + $this->expectException(Exception::class); + + $configuration->filter(); + } + + #[TestDox('--exclude-filter string')] + public function testExcludeFilter(): void + { + $configuration = (new Builder)->fromParameters(['--exclude-filter', 'string']); + + $this->assertTrue($configuration->hasExcludeFilter()); + $this->assertSame('string', $configuration->excludeFilter()); + } + + public function testExcludeFilterMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExcludeFilter()); + + $this->expectException(Exception::class); + + $configuration->excludeFilter(); + } + + #[TestDox('--testsuite string')] + public function testTestSuite(): void + { + $configuration = (new Builder)->fromParameters(['--testsuite', 'string']); + + $this->assertTrue($configuration->hasTestSuite()); + $this->assertSame('string', $configuration->testSuite()); + } + + public function testTestSuiteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestSuite()); + + $this->expectException(Exception::class); + + $configuration->testSuite(); + } + + #[TestDox('--exclude-testsuite string')] + public function testExcludeTestSuite(): void + { + $configuration = (new Builder)->fromParameters(['--exclude-testsuite', 'string']); + + $this->assertTrue($configuration->hasExcludedTestSuite()); + $this->assertSame('string', $configuration->excludedTestSuite()); + } + + public function testExcludeTestSuiteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExcludedTestSuite()); + + $this->expectException(Exception::class); + + $configuration->excludedTestSuite(); + } + + #[TestDox('--generate-baseline file')] + public function testGenerateBaseline(): void + { + $configuration = (new Builder)->fromParameters(['--generate-baseline', 'file']); + + $this->assertTrue($configuration->hasGenerateBaseline()); + $this->assertStringEndsWith('file', $configuration->generateBaseline()); + } + + #[TestDox('--generate-baseline /path/to/file')] + public function testGenerateBaselineWithPathToFile(): void + { + $configuration = (new Builder)->fromParameters(['--generate-baseline', '/path/to/file']); + + $this->assertTrue($configuration->hasGenerateBaseline()); + $this->assertSame('/path/to/file', $configuration->generateBaseline()); + } + + public function testGenerateBaselineMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasGenerateBaseline()); + + $this->expectException(Exception::class); + + $configuration->generateBaseline(); + } + + #[TestDox('--use-baseline file')] + public function testUseBaseline(): void + { + $configuration = (new Builder)->fromParameters(['--use-baseline', 'file']); + + $this->assertTrue($configuration->hasUseBaseline()); + $this->assertStringEndsWith('file', $configuration->useBaseline()); + } + + #[TestDox('--use-baseline /path/to/file')] + public function testUseBaselineWithPathToFile(): void + { + $configuration = (new Builder)->fromParameters(['--use-baseline', '/path/to/file']); + + $this->assertTrue($configuration->hasUseBaseline()); + $this->assertSame('/path/to/file', $configuration->useBaseline()); + } + + public function testUseBaselineMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasUseBaseline()); + + $this->expectException(Exception::class); + + $configuration->useBaseline(); + } + + #[TestDox('--ignore-baseline')] + public function testIgnoreBaseline(): void + { + $configuration = (new Builder)->fromParameters(['--ignore-baseline']); + + $this->assertTrue($configuration->ignoreBaseline()); + } + + #[TestDox('--generate-configuration')] + public function testGenerateConfiguration(): void + { + $configuration = (new Builder)->fromParameters(['--generate-configuration']); + + $this->assertTrue($configuration->generateConfiguration()); + } + + #[TestDox('--migrate-configuration')] + public function testMigrateConfiguration(): void + { + $configuration = (new Builder)->fromParameters(['--migrate-configuration']); + + $this->assertTrue($configuration->migrateConfiguration()); + } + + #[TestDox('--group string')] + public function testGroup(): void + { + $configuration = (new Builder)->fromParameters(['--group', 'string']); + + $this->assertTrue($configuration->hasGroups()); + $this->assertSame(['string'], $configuration->groups()); + } + + #[TestDox('--group string --group another-string')] + public function testGroups(): void + { + $configuration = (new Builder)->fromParameters(['--group', 'string', '--group', 'another-string']); + + $this->assertTrue($configuration->hasGroups()); + $this->assertSame(['string', 'another-string'], $configuration->groups()); + } + + public function testGroupMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasGroups()); + + $this->expectException(Exception::class); + + $configuration->groups(); + } + + #[TestDox('--exclude-group string')] + public function testExcludeGroup(): void + { + $configuration = (new Builder)->fromParameters(['--exclude-group', 'string']); + + $this->assertTrue($configuration->hasExcludeGroups()); + $this->assertSame(['string'], $configuration->excludeGroups()); + } + + #[TestDox('--exclude-group string --exclude-group another-string')] + public function testExcludeGroups(): void + { + $configuration = (new Builder)->fromParameters(['--exclude-group', 'string', '--exclude-group', 'another-string']); + + $this->assertTrue($configuration->hasExcludeGroups()); + $this->assertSame(['string', 'another-string'], $configuration->excludeGroups()); + } + + public function testExcludeGroupMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasGroups()); + + $this->expectException(Exception::class); + + $configuration->excludeGroups(); + } + + #[TestDox('--covers Foo\\Bar\\Baz')] + public function testCovers(): void + { + $configuration = (new Builder)->fromParameters(['--covers', 'Foo\\Bar\\Baz']); + + $this->assertTrue($configuration->hasTestsCovering()); + $this->assertSame(['foo\\bar\\baz'], $configuration->testsCovering()); + } + + public function testCoversMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestsCovering()); + + $this->expectException(Exception::class); + + $configuration->testsCovering(); + } + + #[TestDox('--uses Foo\\Bar\\Baz')] + public function testUses(): void + { + $configuration = (new Builder)->fromParameters(['--uses', 'Foo\\Bar\\Baz']); + + $this->assertTrue($configuration->hasTestsUsing()); + $this->assertSame(['foo\\bar\\baz'], $configuration->testsUsing()); + } + + public function testUsesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestsUsing()); + + $this->expectException(Exception::class); + + $configuration->testsUsing(); + } + + #[TestDox('--requires-php-extension extension')] + public function testRequiresPhpExtension(): void + { + $configuration = (new Builder)->fromParameters(['--requires-php-extension', 'extension']); + + $this->assertTrue($configuration->hasTestsRequiringPhpExtension()); + $this->assertSame(['extension'], $configuration->testsRequiringPhpExtension()); + } + + public function testRequiresPhpExtensionMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestsRequiringPhpExtension()); + + $this->expectException(Exception::class); + + $configuration->testsRequiringPhpExtension(); + } + + #[TestDox('--test-suffix string')] + public function testTestSuffix(): void + { + $configuration = (new Builder)->fromParameters(['--test-suffix', 'string']); + + $this->assertTrue($configuration->hasTestSuffixes()); + $this->assertSame(['string'], $configuration->testSuffixes()); + } + + #[TestDox('--test-suffix string --test-suffix another-string')] + public function testTestSuffixes(): void + { + $configuration = (new Builder)->fromParameters(['--test-suffix', 'string', '--test-suffix', 'another-string']); + + $this->assertTrue($configuration->hasTestSuffixes()); + $this->assertSame(['string', 'another-string'], $configuration->testSuffixes()); + } + + public function testTestSuffixMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestSuffixes()); + + $this->expectException(Exception::class); + + $configuration->testSuffixes(); + } + + #[TestDox('--include-path string')] + public function testIncludePath(): void + { + $configuration = (new Builder)->fromParameters(['--include-path', 'string']); + + $this->assertTrue($configuration->hasIncludePath()); + $this->assertSame('string', $configuration->includePath()); + } + + public function testIncludePathMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasIncludePath()); + + $this->expectException(Exception::class); + + $configuration->includePath(); + } + + #[TestDox('--list-groups')] + public function testListGroups(): void + { + $configuration = (new Builder)->fromParameters(['--list-groups']); + + $this->assertTrue($configuration->listGroups()); + } + + #[TestDox('--list-suites')] + public function testListSuites(): void + { + $configuration = (new Builder)->fromParameters(['--list-suites']); + + $this->assertTrue($configuration->listSuites()); + } + + #[TestDox('--list-test-files')] + public function testListTestFiles(): void + { + $configuration = (new Builder)->fromParameters(['--list-test-files']); + + $this->assertTrue($configuration->listTestFiles()); + } + + #[TestDox('--list-tests')] + public function testListTests(): void + { + $configuration = (new Builder)->fromParameters(['--list-tests']); + + $this->assertTrue($configuration->listTests()); + } + + #[TestDox('--list-tests-xml file')] + public function testListTestsXml(): void + { + $configuration = (new Builder)->fromParameters(['--list-tests-xml', 'file']); + + $this->assertTrue($configuration->hasListTestsXml()); + $this->assertSame('file', $configuration->listTestsXml()); + } + + public function testListTestsXmlMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasListTestsXml()); + + $this->expectException(Exception::class); + + $configuration->listTestsXml(); + } + + #[TestDox('--log-events-text file')] + public function testEventsText(): void + { + $configuration = (new Builder)->fromParameters(['--log-events-text', 'file']); + + $this->assertTrue($configuration->hasLogEventsText()); + $this->assertStringEndsWith('file', $configuration->logEventsText()); + } + + #[TestDox('--log-events-text /invalid/path')] + public function testEventsTextInvalidPath(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('The path "/invalid/path" specified for the --log-events-text option could not be resolved'); + + (new Builder)->fromParameters(['--log-events-text', '/invalid/path']); + } + + public function testEventsTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasLogEventsText()); + + $this->expectException(Exception::class); + + $configuration->logEventsText(); + } + + #[TestDox('--log-events-verbose-text file')] + public function testEventsVerboseText(): void + { + $configuration = (new Builder)->fromParameters(['--log-events-verbose-text', 'file']); + + $this->assertTrue($configuration->hasLogEventsVerboseText()); + $this->assertStringEndsWith('file', $configuration->logEventsVerboseText()); + } + + #[TestDox('--log-events-verbose-text /invalid/path')] + public function testEventsVerboseTextInvalidPath(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('The path "/invalid/path" specified for the --log-events-verbose-text option could not be resolved'); + + (new Builder)->fromParameters(['--log-events-verbose-text', '/invalid/path']); + } + + public function testEventsVerboseTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasLogEventsVerboseText()); + + $this->expectException(Exception::class); + + $configuration->logEventsVerboseText(); + } + + #[TestDox('--log-junit file')] + public function testLogJunit(): void + { + $configuration = (new Builder)->fromParameters(['--log-junit', 'file']); + + $this->assertTrue($configuration->hasJunitLogfile()); + $this->assertSame('file', $configuration->junitLogfile()); + } + + public function testLogJunitMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasJunitLogfile()); + + $this->expectException(Exception::class); + + $configuration->junitLogfile(); + } + + #[TestDox('--log-otr file')] + public function testLogOtr(): void + { + $configuration = (new Builder)->fromParameters(['--log-otr', 'file']); + + $this->assertTrue($configuration->hasOtrLogfile()); + $this->assertSame('file', $configuration->otrLogfile()); + } + + public function testLogOtrMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasOtrLogfile()); + + $this->expectException(Exception::class); + + $configuration->otrLogfile(); + } + + #[TestDox('--log-teamcity file')] + public function testLogTeamcity(): void + { + $configuration = (new Builder)->fromParameters(['--log-teamcity', 'file']); + + $this->assertTrue($configuration->hasTeamcityLogfile()); + $this->assertSame('file', $configuration->teamcityLogfile()); + } + + public function testLogTeamcityMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTeamcityLogfile()); + + $this->expectException(Exception::class); + + $configuration->teamcityLogfile(); + } + + #[TestDox('--order-by default')] + public function testOrderByDefault(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'default']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_DEFAULT, $configuration->executionOrder()); + $this->assertTrue($configuration->hasExecutionOrderDefects()); + $this->assertSame(TestSuiteSorter::ORDER_DEFAULT, $configuration->executionOrderDefects()); + $this->assertTrue($configuration->resolveDependencies()); + } + + #[TestDox('--order-by defects')] + public function testOrderByDefects(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'defects']); + + $this->assertFalse($configuration->hasExecutionOrder()); + $this->assertTrue($configuration->hasExecutionOrderDefects()); + $this->assertSame(TestSuiteSorter::ORDER_DEFECTS_FIRST, $configuration->executionOrderDefects()); + $this->assertFalse($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends')] + public function testOrderByDepends(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends']); + + $this->assertFalse($configuration->hasExecutionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by duration')] + public function testOrderByDuration(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'duration']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_DURATION, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertFalse($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by random')] + public function testOrderByRandom(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'random']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_RANDOMIZED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertFalse($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by reverse')] + public function testOrderByReverse(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'reverse']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_REVERSED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertFalse($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by size')] + public function testOrderBySize(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'size']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_SIZE, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertFalse($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends,defects')] + public function testOrderByDependsDefects(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends,defects']); + + $this->assertFalse($configuration->hasExecutionOrder()); + $this->assertTrue($configuration->hasExecutionOrderDefects()); + $this->assertSame(TestSuiteSorter::ORDER_DEFECTS_FIRST, $configuration->executionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends,duration')] + public function testOrderByDependsDuration(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends,duration']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_DURATION, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends,random')] + public function testOrderByDependsRandom(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends,random']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_RANDOMIZED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends,reverse')] + public function testOrderByDependsReverse(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends,reverse']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_REVERSED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by depends,size')] + public function testOrderByDependsSize(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'depends,size']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_SIZE, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + } + + #[TestDox('--order-by no-depends')] + public function testOrderByNoDepends(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends']); + + $this->assertFalse($configuration->hasExecutionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by no-depends,defects')] + public function testOrderByNoDependsDefects(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends,defects']); + + $this->assertFalse($configuration->hasExecutionOrder()); + $this->assertTrue($configuration->hasExecutionOrderDefects()); + $this->assertSame(TestSuiteSorter::ORDER_DEFECTS_FIRST, $configuration->executionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by no-depends,duration')] + public function testOrderByNoDependsDuration(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends,duration']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_DURATION, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by no-depends,random')] + public function testOrderByNoDependsRandom(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends,random']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_RANDOMIZED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by no-depends,reverse')] + public function testOrderByNoDependsReverse(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends,reverse']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_REVERSED, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by no-depends,size')] + public function testOrderByNoDependsSize(): void + { + $configuration = (new Builder)->fromParameters(['--order-by', 'no-depends,size']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_SIZE, $configuration->executionOrder()); + $this->assertFalse($configuration->hasExecutionOrderDefects()); + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--order-by invalid')] + public function testOrderByInvalid(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('unrecognized --order-by option: invalid'); + + (new Builder)->fromParameters(['--order-by', 'invalid']); + } + + public function testExecutionOrderMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExecutionOrder()); + + $this->expectException(Exception::class); + + $configuration->executionOrder(); + } + + public function testExecutionOrderDefectsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExecutionOrderDefects()); + + $this->expectException(Exception::class); + + $configuration->executionOrderDefects(); + } + + public function testResolveDependenciesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasResolveDependencies()); + + $this->expectException(Exception::class); + + $configuration->resolveDependencies(); + } + + #[TestDox('--process-isolation')] + public function testProcessIsolation(): void + { + $configuration = (new Builder)->fromParameters(['--process-isolation']); + + $this->assertTrue($configuration->hasProcessIsolation()); + $this->assertTrue($configuration->processIsolation()); + } + + public function testProcessIsolationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasProcessIsolation()); + + $this->expectException(Exception::class); + + $configuration->processIsolation(); + } + + #[TestDox('--stderr')] + public function testStderr(): void + { + $configuration = (new Builder)->fromParameters(['--stderr']); + + $this->assertTrue($configuration->hasStderr()); + $this->assertTrue($configuration->stderr()); + } + + public function testStderrMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStderr()); + + $this->expectException(Exception::class); + + $configuration->stderr(); + } + + #[TestDox('--fail-on-all-issues')] + public function testFailOnAllIssues(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-all-issues']); + + $this->assertTrue($configuration->hasFailOnAllIssues()); + $this->assertTrue($configuration->failOnAllIssues()); + } + + public function testFailOnAllIssuesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnAllIssues()); + + $this->expectException(Exception::class); + + $configuration->failOnAllIssues(); + } + + #[TestDox('--fail-on-deprecation')] + public function testFailOnDeprecation(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-deprecation']); + + $this->assertTrue($configuration->hasFailOnDeprecation()); + $this->assertTrue($configuration->failOnDeprecation()); + } + + public function testFailOnDeprecationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnDeprecation()); + + $this->expectException(Exception::class); + + $configuration->failOnDeprecation(); + } + + #[TestDox('--fail-on-phpunit-deprecation')] + public function testFailOnPhpunitDeprecation(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-phpunit-deprecation']); + + $this->assertTrue($configuration->hasFailOnPhpunitDeprecation()); + $this->assertTrue($configuration->failOnPhpunitDeprecation()); + } + + public function testFailOnPhpunitDeprecationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnPhpunitDeprecation()); + + $this->expectException(Exception::class); + + $configuration->failOnPhpunitDeprecation(); + } + + #[TestDox('--fail-on-phpunit-notice')] + public function testFailOnPhpunitNotice(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-phpunit-notice']); + + $this->assertTrue($configuration->hasFailOnPhpunitNotice()); + $this->assertTrue($configuration->failOnPhpunitNotice()); + } + + public function testFailOnPhpunitNoticeMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnPhpunitNotice()); + + $this->expectException(Exception::class); + + $configuration->failOnPhpunitNotice(); + } + + #[TestDox('--fail-on-phpunit-warning')] + public function testFailOnPhpunitWarning(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-phpunit-warning']); + + $this->assertTrue($configuration->hasFailOnPhpunitWarning()); + $this->assertTrue($configuration->failOnPhpunitWarning()); + } + + public function testFailOnPhpunitWarningMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnPhpunitWarning()); + + $this->expectException(Exception::class); + + $configuration->failOnPhpunitWarning(); + } + + #[TestDox('--fail-on-empty-test-suite')] + public function testFailOnEmptyTestSuite(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-empty-test-suite']); + + $this->assertTrue($configuration->hasFailOnEmptyTestSuite()); + $this->assertTrue($configuration->failOnEmptyTestSuite()); + } + + public function testFailOnEmptyTestSuiteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnEmptyTestSuite()); + + $this->expectException(Exception::class); + + $configuration->failOnEmptyTestSuite(); + } + + #[TestDox('--fail-on-incomplete')] + public function testFailOnIncomplete(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-incomplete']); + + $this->assertTrue($configuration->hasFailOnIncomplete()); + $this->assertTrue($configuration->failOnIncomplete()); + } + + public function testFailOnIncompleteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnIncomplete()); + + $this->expectException(Exception::class); + + $configuration->failOnIncomplete(); + } + + #[TestDox('--fail-on-notice')] + public function testFailOnNotice(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-notice']); + + $this->assertTrue($configuration->hasFailOnNotice()); + $this->assertTrue($configuration->failOnNotice()); + } + + public function testFailOnNoticeMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnNotice()); + + $this->expectException(Exception::class); + + $configuration->failOnNotice(); + } + + #[TestDox('--fail-on-risky')] + public function testFailOnRisky(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-risky']); + + $this->assertTrue($configuration->hasFailOnRisky()); + $this->assertTrue($configuration->failOnRisky()); + } + + public function testFailOnRiskyMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnRisky()); + + $this->expectException(Exception::class); + + $configuration->failOnRisky(); + } + + #[TestDox('--fail-on-skipped')] + public function testFailOnSkipped(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-skipped']); + + $this->assertTrue($configuration->hasFailOnSkipped()); + $this->assertTrue($configuration->failOnSkipped()); + } + + public function testFailOnSkippedMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnSkipped()); + + $this->expectException(Exception::class); + + $configuration->failOnSkipped(); + } + + #[TestDox('--fail-on-warning')] + public function testFailOnWarning(): void + { + $configuration = (new Builder)->fromParameters(['--fail-on-warning']); + + $this->assertTrue($configuration->hasFailOnWarning()); + $this->assertTrue($configuration->failOnWarning()); + } + + public function testFailOnWarningMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasFailOnWarning()); + + $this->expectException(Exception::class); + + $configuration->failOnWarning(); + } + + #[TestDox('--do-not-fail-on-deprecation')] + public function testDoNotFailOnDeprecation(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-deprecation']); + + $this->assertTrue($configuration->hasDoNotFailOnDeprecation()); + $this->assertTrue($configuration->doNotFailOnDeprecation()); + } + + public function testDoNotFailOnDeprecationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnDeprecation()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnDeprecation(); + } + + #[TestDox('--do-not-fail-on-phpunit-deprecation')] + public function testDoNotFailOnPhpunitDeprecation(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-phpunit-deprecation']); + + $this->assertTrue($configuration->hasDoNotFailOnPhpunitDeprecation()); + $this->assertTrue($configuration->doNotFailOnPhpunitDeprecation()); + } + + public function testDoNotFailOnPhpunitDeprecationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnPhpunitDeprecation()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnPhpunitDeprecation(); + } + + #[TestDox('--do-not-fail-on-phpunit-notice')] + public function testDoNotFailOnPhpunitNotice(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-phpunit-notice']); + + $this->assertTrue($configuration->hasDoNotFailOnPhpunitNotice()); + $this->assertTrue($configuration->doNotFailOnPhpunitNotice()); + } + + public function testDoNotFailOnPhpunitNoticeMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnPhpunitNotice()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnPhpunitNotice(); + } + + #[TestDox('--do-not-fail-on-phpunit-warning')] + public function testDoNotFailOnPhpunitWarning(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-phpunit-warning']); + + $this->assertTrue($configuration->hasDoNotFailOnPhpunitWarning()); + $this->assertTrue($configuration->doNotFailOnPhpunitWarning()); + } + + public function testDoNotFailOnPhpunitWarningMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnPhpunitWarning()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnPhpunitWarning(); + } + + #[TestDox('--do-not-fail-on-empty-test-suite')] + public function testDoNotFailOnEmptyTestSuite(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-empty-test-suite']); + + $this->assertTrue($configuration->hasDoNotFailOnEmptyTestSuite()); + $this->assertTrue($configuration->doNotFailOnEmptyTestSuite()); + } + + public function testDoNotFailOnEmptyTestSuiteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnEmptyTestSuite()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnEmptyTestSuite(); + } + + #[TestDox('--do-not-fail-on-incomplete')] + public function testDoNotFailOnIncomplete(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-incomplete']); + + $this->assertTrue($configuration->hasDoNotFailOnIncomplete()); + $this->assertTrue($configuration->doNotFailOnIncomplete()); + } + + public function testDoNotFailOnIncompleteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnIncomplete()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnIncomplete(); + } + + #[TestDox('--do-not-fail-on-notice')] + public function testDoNotFailOnNotice(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-notice']); + + $this->assertTrue($configuration->hasDoNotFailOnNotice()); + $this->assertTrue($configuration->doNotFailOnNotice()); + } + + public function testDoNotFailOnNoticeMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnNotice()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnNotice(); + } + + #[TestDox('--do-not-fail-on-risky')] + public function testDoNotFailOnRisky(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-risky']); + + $this->assertTrue($configuration->hasDoNotFailOnRisky()); + $this->assertTrue($configuration->doNotFailOnRisky()); + } + + public function testDoNotFailOnRiskyMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnRisky()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnRisky(); + } + + #[TestDox('--do-not-fail-on-skipped')] + public function testDoNotFailOnSkipped(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-skipped']); + + $this->assertTrue($configuration->hasDoNotFailOnSkipped()); + $this->assertTrue($configuration->doNotFailOnSkipped()); + } + + public function testDoNotFailOnSkippedMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnSkipped()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnSkipped(); + } + + #[TestDox('--do-not-fail-on-warning')] + public function testDoNotFailOnWarning(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-fail-on-warning']); + + $this->assertTrue($configuration->hasDoNotFailOnWarning()); + $this->assertTrue($configuration->doNotFailOnWarning()); + } + + public function testDoNotFailOnWarningMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDoNotFailOnWarning()); + + $this->expectException(Exception::class); + + $configuration->doNotFailOnWarning(); + } + + #[TestDox('--stop-on-defect')] + public function testStopOnDefect(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-defect']); + + $this->assertTrue($configuration->hasStopOnDefect()); + $this->assertTrue($configuration->stopOnDefect()); + } + + public function testStopOnDefectMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnDefect()); + + $this->expectException(Exception::class); + + $configuration->stopOnDefect(); + } + + #[TestDox('--stop-on-deprecation')] + public function testStopOnDeprecation(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-deprecation']); + + $this->assertTrue($configuration->hasStopOnDeprecation()); + $this->assertTrue($configuration->stopOnDeprecation()); + + $this->expectException(Exception::class); + + $configuration->specificDeprecationToStopOn(); + } + + #[TestDox('--stop-on-deprecation=message')] + public function testStopOnDeprecationMessage(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-deprecation=message']); + + $this->assertTrue($configuration->hasStopOnDeprecation()); + $this->assertTrue($configuration->stopOnDeprecation()); + $this->assertTrue($configuration->hasSpecificDeprecationToStopOn()); + $this->assertSame('message', $configuration->specificDeprecationToStopOn()); + } + + public function testStopOnDeprecationMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnDeprecation()); + + $this->expectException(Exception::class); + + $configuration->stopOnDeprecation(); + } + + #[TestDox('--stop-on-error')] + public function testStopOnError(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-error']); + + $this->assertTrue($configuration->hasStopOnError()); + $this->assertTrue($configuration->stopOnError()); + } + + public function testStopOnErrorMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnError()); + + $this->expectException(Exception::class); + + $configuration->stopOnError(); + } + + #[TestDox('--stop-on-failure')] + public function testStopOnFailure(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-failure']); + + $this->assertTrue($configuration->hasStopOnFailure()); + $this->assertTrue($configuration->stopOnFailure()); + } + + public function testStopOnFailureMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnFailure()); + + $this->expectException(Exception::class); + + $configuration->stopOnFailure(); + } + + #[TestDox('--stop-on-incomplete')] + public function testStopOnIncomplete(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-incomplete']); + + $this->assertTrue($configuration->hasStopOnIncomplete()); + $this->assertTrue($configuration->stopOnIncomplete()); + } + + public function testStopOnIncompleteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnIncomplete()); + + $this->expectException(Exception::class); + + $configuration->stopOnIncomplete(); + } + + #[TestDox('--stop-on-notice')] + public function testStopOnNotice(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-notice']); + + $this->assertTrue($configuration->hasStopOnNotice()); + $this->assertTrue($configuration->stopOnNotice()); + } + + public function testStopOnNoticeMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnNotice()); + + $this->expectException(Exception::class); + + $configuration->stopOnNotice(); + } + + #[TestDox('--stop-on-risky')] + public function testStopOnRisky(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-risky']); + + $this->assertTrue($configuration->hasStopOnRisky()); + $this->assertTrue($configuration->stopOnRisky()); + } + + public function testStopOnRiskyMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnRisky()); + + $this->expectException(Exception::class); + + $configuration->stopOnRisky(); + } + + #[TestDox('--stop-on-skipped')] + public function testStopOnSkipped(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-skipped']); + + $this->assertTrue($configuration->hasStopOnSkipped()); + $this->assertTrue($configuration->stopOnSkipped()); + } + + public function testStopOnSkippedMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnSkipped()); + + $this->expectException(Exception::class); + + $configuration->stopOnSkipped(); + } + + #[TestDox('--stop-on-warning')] + public function testStopOnWarning(): void + { + $configuration = (new Builder)->fromParameters(['--stop-on-warning']); + + $this->assertTrue($configuration->hasStopOnWarning()); + $this->assertTrue($configuration->stopOnWarning()); + } + + public function testStopOnWarningMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStopOnWarning()); + + $this->expectException(Exception::class); + + $configuration->stopOnWarning(); + } + + #[TestDox('--teamcity')] + public function testTeamcity(): void + { + $configuration = (new Builder)->fromParameters(['--teamcity']); + + $this->assertTrue($configuration->hasTeamCityPrinter()); + $this->assertTrue($configuration->teamCityPrinter()); + } + + public function testTeamcityMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTeamCityPrinter()); + + $this->expectException(Exception::class); + + $configuration->teamCityPrinter(); + } + + #[TestDox('--testdox')] + public function testTestDox(): void + { + $configuration = (new Builder)->fromParameters(['--testdox']); + + $this->assertTrue($configuration->hasTestDoxPrinter()); + $this->assertTrue($configuration->testdoxPrinter()); + } + + public function testTestDoxMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestDoxPrinter()); + + $this->expectException(Exception::class); + + $configuration->testdoxPrinter(); + } + + #[TestDox('--testdox-summary')] + public function testTestDoxPrinterSummary(): void + { + $configuration = (new Builder)->fromParameters(['--testdox-summary']); + + $this->assertTrue($configuration->hasTestDoxPrinterSummary()); + $this->assertTrue($configuration->testdoxPrinterSummary()); + } + + public function testTestDoxPrinterSummaryMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestDoxPrinterSummary()); + + $this->expectException(Exception::class); + + $configuration->testdoxPrinterSummary(); + } + + #[TestDox('--testdox-html file')] + public function testTestDoxHtml(): void + { + $configuration = (new Builder)->fromParameters(['--testdox-html', 'file']); + + $this->assertTrue($configuration->hasTestdoxHtmlFile()); + $this->assertSame('file', $configuration->testdoxHtmlFile()); + } + + public function testTestDoxHtmlMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestdoxHtmlFile()); + + $this->expectException(Exception::class); + + $configuration->testdoxHtmlFile(); + } + + #[TestDox('--testdox-text file')] + public function testTestDoxText(): void + { + $configuration = (new Builder)->fromParameters(['--testdox-text', 'file']); + + $this->assertTrue($configuration->hasTestdoxTextFile()); + $this->assertSame('file', $configuration->testdoxTextFile()); + } + + public function testTestDoxTextMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasTestdoxTextFile()); + + $this->expectException(Exception::class); + + $configuration->testdoxTextFile(); + } + + #[TestDox('--no-configuration')] + public function testNoConfiguration(): void + { + $configuration = (new Builder)->fromParameters(['--no-configuration']); + + $this->assertFalse($configuration->useDefaultConfiguration()); + } + + #[TestDox('--no-extensions')] + public function testNoExtensions(): void + { + $configuration = (new Builder)->fromParameters(['--no-extensions']); + + $this->assertTrue($configuration->hasNoExtensions()); + $this->assertTrue($configuration->noExtensions()); + } + + public function testNoExtensionsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoExtensions()); + + $this->expectException(Exception::class); + + $configuration->noExtensions(); + } + + #[TestDox('--no-coverage')] + public function testNoCoverage(): void + { + $configuration = (new Builder)->fromParameters(['--no-coverage']); + + $this->assertTrue($configuration->hasNoCoverage()); + $this->assertTrue($configuration->noCoverage()); + } + + public function testNoCoverageMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoCoverage()); + + $this->expectException(Exception::class); + + $configuration->noCoverage(); + } + + #[TestDox('--no-logging')] + public function testNoLogging(): void + { + $configuration = (new Builder)->fromParameters(['--no-logging']); + + $this->assertTrue($configuration->hasNoLogging()); + $this->assertTrue($configuration->noLogging()); + } + + public function testNoLoggingMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoLogging()); + + $this->expectException(Exception::class); + + $configuration->noLogging(); + } + + #[TestDox('--no-output')] + public function testNoOutput(): void + { + $configuration = (new Builder)->fromParameters(['--no-output']); + + $this->assertTrue($configuration->hasNoOutput()); + $this->assertTrue($configuration->noOutput()); + } + + public function testNoOutputMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoOutput()); + + $this->expectException(Exception::class); + + $configuration->noOutput(); + } + + #[TestDox('--no-progress')] + public function testNoProgress(): void + { + $configuration = (new Builder)->fromParameters(['--no-progress']); + + $this->assertTrue($configuration->hasNoProgress()); + $this->assertTrue($configuration->noProgress()); + } + + public function testNoProgressMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoProgress()); + + $this->expectException(Exception::class); + + $configuration->noProgress(); + } + + #[TestDox('--no-results')] + public function testNoResults(): void + { + $configuration = (new Builder)->fromParameters(['--no-results']); + + $this->assertTrue($configuration->hasNoResults()); + $this->assertTrue($configuration->noResults()); + } + + public function testNoResultsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasNoResults()); + + $this->expectException(Exception::class); + + $configuration->noResults(); + } + + #[TestDox('--globals-backup')] + public function testGlobalsBackup(): void + { + $configuration = (new Builder)->fromParameters(['--globals-backup']); + + $this->assertTrue($configuration->hasBackupGlobals()); + $this->assertTrue($configuration->backupGlobals()); + } + + public function testGlobalsBackupMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasBackupGlobals()); + + $this->expectException(Exception::class); + + $configuration->backupGlobals(); + } + + #[TestDox('--static-backup')] + public function testStaticBackup(): void + { + $configuration = (new Builder)->fromParameters(['--static-backup']); + + $this->assertTrue($configuration->hasBackupStaticProperties()); + $this->assertTrue($configuration->backupStaticProperties()); + } + + public function testStaticBackupMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasBackupStaticProperties()); + + $this->expectException(Exception::class); + + $configuration->backupStaticProperties(); + } + + #[TestDox('--atleast-version string')] + public function testAtLeastVersion(): void + { + $configuration = (new Builder)->fromParameters(['--atleast-version', 'string']); + + $this->assertTrue($configuration->hasAtLeastVersion()); + $this->assertSame('string', $configuration->atLeastVersion()); + } + + public function testAtLeastVersionMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasAtLeastVersion()); + + $this->expectException(Exception::class); + + $configuration->atLeastVersion(); + } + + #[TestDox('--version')] + public function testVersion(): void + { + $configuration = (new Builder)->fromParameters(['--version']); + + $this->assertTrue($configuration->version()); + } + + #[TestDox('--do-not-report-useless-tests')] + public function testDoNotReportUselessTests(): void + { + $configuration = (new Builder)->fromParameters(['--do-not-report-useless-tests']); + + $this->assertTrue($configuration->hasReportUselessTests()); + $this->assertFalse($configuration->reportUselessTests()); + } + + public function testDoNotReportUselessTestsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasReportUselessTests()); + + $this->expectException(Exception::class); + + $configuration->reportUselessTests(); + } + + #[TestDox('--strict-coverage')] + public function testStrictCoverage(): void + { + $configuration = (new Builder)->fromParameters(['--strict-coverage']); + + $this->assertTrue($configuration->hasStrictCoverage()); + $this->assertTrue($configuration->strictCoverage()); + } + + public function testStrictCoverageMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasStrictCoverage()); + + $this->expectException(Exception::class); + + $configuration->strictCoverage(); + } + + #[TestDox('--disable-coverage-ignore')] + public function testDisableCoverageIgnore(): void + { + $configuration = (new Builder)->fromParameters(['--disable-coverage-ignore']); + + $this->assertTrue($configuration->hasDisableCodeCoverageIgnore()); + $this->assertTrue($configuration->disableCodeCoverageIgnore()); + } + + public function testDisableCoverageIgnoreMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisableCodeCoverageIgnore()); + + $this->expectException(Exception::class); + + $configuration->disableCodeCoverageIgnore(); + } + + #[TestDox('--strict-global-state')] + public function testStrictGlobalState(): void + { + $configuration = (new Builder)->fromParameters(['--strict-global-state']); + + $this->assertTrue($configuration->hasBeStrictAboutChangesToGlobalState()); + $this->assertTrue($configuration->beStrictAboutChangesToGlobalState()); + } + + public function testStrictGlobalStateMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasBeStrictAboutChangesToGlobalState()); + + $this->expectException(Exception::class); + + $configuration->beStrictAboutChangesToGlobalState(); + } + + #[TestDox('--disallow-test-output')] + public function testDisallowTestOutput(): void + { + $configuration = (new Builder)->fromParameters(['--disallow-test-output']); + + $this->assertTrue($configuration->hasDisallowTestOutput()); + $this->assertTrue($configuration->disallowTestOutput()); + } + + public function testDisallowTestOutputMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisallowTestOutput()); + + $this->expectException(Exception::class); + + $configuration->disallowTestOutput(); + } + + #[TestDox('--display-all-issues')] + public function testDisplayAllIssues(): void + { + $configuration = (new Builder)->fromParameters(['--display-all-issues']); + + $this->assertTrue($configuration->hasDisplayDetailsOnAllIssues()); + $this->assertTrue($configuration->displayDetailsOnAllIssues()); + } + + public function testDisplayAllIssuesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnAllIssues()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnAllIssues(); + } + + #[TestDox('--display-incomplete')] + public function testDisplayIncomplete(): void + { + $configuration = (new Builder)->fromParameters(['--display-incomplete']); + + $this->assertTrue($configuration->hasDisplayDetailsOnIncompleteTests()); + $this->assertTrue($configuration->displayDetailsOnIncompleteTests()); + } + + public function testDisplayIncompleteMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnIncompleteTests()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnIncompleteTests(); + } + + #[TestDox('--display-skipped')] + public function testDisplaySkipped(): void + { + $configuration = (new Builder)->fromParameters(['--display-skipped']); + + $this->assertTrue($configuration->hasDisplayDetailsOnSkippedTests()); + $this->assertTrue($configuration->displayDetailsOnSkippedTests()); + } + + public function testDisplaySkippedMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnSkippedTests()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnSkippedTests(); + } + + #[TestDox('--display-deprecations')] + public function testDisplayDeprecations(): void + { + $configuration = (new Builder)->fromParameters(['--display-deprecations']); + + $this->assertTrue($configuration->hasDisplayDetailsOnTestsThatTriggerDeprecations()); + $this->assertTrue($configuration->displayDetailsOnTestsThatTriggerDeprecations()); + } + + public function testDisplayDeprecationsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnTestsThatTriggerDeprecations()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnTestsThatTriggerDeprecations(); + } + + #[TestDox('--display-phpunit-deprecations')] + public function testDisplayPhpunitDeprecations(): void + { + $configuration = (new Builder)->fromParameters(['--display-phpunit-deprecations']); + + $this->assertTrue($configuration->hasDisplayDetailsOnPhpunitDeprecations()); + $this->assertTrue($configuration->displayDetailsOnPhpunitDeprecations()); + } + + public function testDisplayPhpunitDeprecationsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnPhpunitDeprecations()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnPhpunitDeprecations(); + } + + #[TestDox('--display-phpunit-notices')] + public function testDisplayPhpunitNotices(): void + { + $configuration = (new Builder)->fromParameters(['--display-phpunit-notices']); + + $this->assertTrue($configuration->hasDisplayDetailsOnPhpunitNotices()); + $this->assertTrue($configuration->displayDetailsOnPhpunitNotices()); + } + + public function testDisplayPhpunitNoticesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnPhpunitNotices()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnPhpunitNotices(); + } + + #[TestDox('--display-errors')] + public function testDisplayErrors(): void + { + $configuration = (new Builder)->fromParameters(['--display-errors']); + + $this->assertTrue($configuration->hasDisplayDetailsOnTestsThatTriggerErrors()); + $this->assertTrue($configuration->displayDetailsOnTestsThatTriggerErrors()); + } + + public function testDisplayErrorsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnTestsThatTriggerErrors()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnTestsThatTriggerErrors(); + } + + #[TestDox('--display-notices')] + public function testDisplayNotices(): void + { + $configuration = (new Builder)->fromParameters(['--display-notices']); + + $this->assertTrue($configuration->hasDisplayDetailsOnTestsThatTriggerNotices()); + $this->assertTrue($configuration->displayDetailsOnTestsThatTriggerNotices()); + } + + public function testDisplayNoticesMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnTestsThatTriggerNotices()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnTestsThatTriggerNotices(); + } + + #[TestDox('--display-warnings')] + public function testDisplayWarnings(): void + { + $configuration = (new Builder)->fromParameters(['--display-warnings']); + + $this->assertTrue($configuration->hasDisplayDetailsOnTestsThatTriggerWarnings()); + $this->assertTrue($configuration->displayDetailsOnTestsThatTriggerWarnings()); + } + + public function testDisplayWarningsMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDisplayDetailsOnTestsThatTriggerWarnings()); + + $this->expectException(Exception::class); + + $configuration->displayDetailsOnTestsThatTriggerWarnings(); + } + + #[TestDox('--default-time-limit ')] + public function testDefaultTimeLimit(): void + { + $configuration = (new Builder)->fromParameters(['--default-time-limit', '10']); + + $this->assertTrue($configuration->hasDefaultTimeLimit()); + $this->assertSame(10, $configuration->defaultTimeLimit()); + } + + public function testDefaultTimeLimitMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasDefaultTimeLimit()); + + $this->expectException(Exception::class); + + $configuration->defaultTimeLimit(); + } + + #[TestDox('--enforce-time-limit')] + public function testEnforceTimeLimit(): void + { + $configuration = (new Builder)->fromParameters(['--enforce-time-limit']); + + $this->assertTrue($configuration->hasEnforceTimeLimit()); + $this->assertTrue($configuration->enforceTimeLimit()); + } + + public function testEnforceTimeLimitMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasEnforceTimeLimit()); + + $this->expectException(Exception::class); + + $configuration->enforceTimeLimit(); + } + + #[TestDox('--reverse-list')] + public function testReverseList(): void + { + $configuration = (new Builder)->fromParameters(['--reverse-list']); + + $this->assertTrue($configuration->hasReverseList()); + $this->assertTrue($configuration->reverseList()); + } + + public function testReverseListMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasReverseList()); + + $this->expectException(Exception::class); + + $configuration->reverseList(); + } + + #[TestDox('--check-version')] + public function testCheckVersion(): void + { + $configuration = (new Builder)->fromParameters(['--check-version']); + + $this->assertTrue($configuration->checkVersion()); + } + + #[TestDox('--coverage-filter directory')] + public function testCoverageFilterDirectory(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-filter', 'directory']); + + $this->assertTrue($configuration->hasCoverageFilter()); + $this->assertSame(['directory'], $configuration->coverageFilter()); + } + + #[TestDox('--coverage-filter directory --coverage-filter another-directory')] + public function testCoverageFilterDirectories(): void + { + $configuration = (new Builder)->fromParameters(['--coverage-filter', 'directory', '--coverage-filter', 'another-directory']); + + $this->assertTrue($configuration->hasCoverageFilter()); + $this->assertSame(['directory', 'another-directory'], $configuration->coverageFilter()); + } + + public function testCoverageFilterMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasCoverageFilter()); + + $this->expectException(Exception::class); + + $configuration->coverageFilter(); + } + + #[TestDox('--random-order')] + public function testRandomOrder(): void + { + $configuration = (new Builder)->fromParameters(['--random-order']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_RANDOMIZED, $configuration->executionOrder()); + } + + #[TestDox('--resolve-dependencies')] + public function testResolveDependencies(): void + { + $configuration = (new Builder)->fromParameters(['--resolve-dependencies']); + + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertTrue($configuration->resolveDependencies()); + } + + #[TestDox('--ignore-dependencies')] + public function testIgnoreDependencies(): void + { + $configuration = (new Builder)->fromParameters(['--ignore-dependencies']); + + $this->assertTrue($configuration->hasResolveDependencies()); + $this->assertFalse($configuration->resolveDependencies()); + } + + #[TestDox('--reverse-order')] + public function testReverseOrder(): void + { + $configuration = (new Builder)->fromParameters(['--reverse-order']); + + $this->assertTrue($configuration->hasExecutionOrder()); + $this->assertSame(TestSuiteSorter::ORDER_REVERSED, $configuration->executionOrder()); + } + + #[TestDox('--random-order-seed')] + public function testRandomOrderSeed(): void + { + $configuration = (new Builder)->fromParameters(['--random-order-seed', '1234']); + + $this->assertTrue($configuration->hasRandomOrderSeed()); + $this->assertSame(1234, $configuration->randomOrderSeed()); + } + + public function testRandomOrderSeedMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasRandomOrderSeed()); + + $this->expectException(Exception::class); + + $configuration->randomOrderSeed(); + } + + #[TestDox('--debug')] + public function testDebug(): void + { + $configuration = (new Builder)->fromParameters(['--debug']); + + $this->assertTrue($configuration->debug()); + } + + #[TestDox('--with-telemetry')] + public function testWithTelemetry(): void + { + $configuration = (new Builder)->fromParameters(['--with-telemetry']); + + $this->assertTrue($configuration->withTelemetry()); + } + + #[TestDox('--extension')] + public function testExtension(): void + { + $configuration = (new Builder)->fromParameters(['--extension', 'ExtensionClass']); + + $this->assertTrue($configuration->hasExtensions()); + $this->assertSame(['ExtensionClass'], $configuration->extensions()); + } + + public function testExtensionMayNotBeConfigured(): void + { + $configuration = (new Builder)->fromParameters([]); + + $this->assertFalse($configuration->hasExtensions()); + + $this->expectException(Exception::class); + + $configuration->extensions(); + } + + public function testInvalidOption(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('Unknown option "--invalid-option"'); + + (new Builder)->fromParameters(['--invalid-option']); + } +} diff --git a/tests/unit/TextUI/Configuration/MergerTest.php b/tests/unit/TextUI/Configuration/MergerTest.php new file mode 100644 index 00000000000..5b7edd9eba2 --- /dev/null +++ b/tests/unit/TextUI/Configuration/MergerTest.php @@ -0,0 +1,137 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function uniqid; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\CliArguments\Builder; +use PHPUnit\TextUI\Configuration\Merger; + +#[CoversClass(Merger::class)] +#[Medium] +final class MergerTest extends TestCase +{ + public function testNoLoggingShouldOnlyAffectXmlConfiguration(): void + { + $junitLog = uniqid('junit_log_'); + $fromFile = (new Loader)->load(TEST_FILES_PATH . 'configuration_logging.xml'); + + $this->assertTrue($fromFile->logging()->hasTeamCity()); + $this->assertTrue($fromFile->logging()->hasTestDoxHtml()); + $this->assertTrue($fromFile->logging()->hasTestDoxText()); + + $this->assertTrue($fromFile->logging()->hasJunit()); + $this->assertNotSame($junitLog, $fromFile->logging()->junit()->target()->path()); + + $fromCli = (new Builder)->fromParameters([ + '--no-logging', + '--log-junit', + $junitLog, + ]); + + $mergedConfig = (new Merger)->merge($fromCli, $fromFile); + + $this->assertFalse($mergedConfig->hasLogfileTeamcity()); + $this->assertFalse($mergedConfig->hasLogfileTestdoxHtml()); + $this->assertFalse($mergedConfig->hasLogfileTestdoxText()); + + $this->assertTrue($mergedConfig->hasLogfileJunit()); + $this->assertSame($junitLog, $mergedConfig->logfileJunit()); + } + + public function testNoCoverageShouldOnlyAffectXmlConfiguration(): void + { + $phpCoverage = uniqid('php_coverage_'); + $fromFile = (new Loader)->load(TEST_FILES_PATH . 'configuration_codecoverage.xml'); + + $this->assertTrue($fromFile->codeCoverage()->hasClover()); + $this->assertTrue($fromFile->codeCoverage()->hasCobertura()); + $this->assertTrue($fromFile->codeCoverage()->hasCrap4j()); + $this->assertTrue($fromFile->codeCoverage()->hasHtml()); + $this->assertTrue($fromFile->codeCoverage()->hasOpenClover()); + $this->assertTrue($fromFile->codeCoverage()->hasText()); + $this->assertTrue($fromFile->codeCoverage()->hasXml()); + + $this->assertTrue($fromFile->codeCoverage()->hasPhp()); + $this->assertNotSame($phpCoverage, $fromFile->codeCoverage()->php()->target()->path()); + + $fromCli = (new Builder)->fromParameters([ + '--no-coverage', + '--coverage-php', + $phpCoverage, + ]); + + $mergedConfig = (new Merger)->merge($fromCli, $fromFile); + + $this->assertFalse($mergedConfig->hasCoverageClover()); + $this->assertFalse($mergedConfig->hasCoverageCobertura()); + $this->assertFalse($mergedConfig->hasCoverageCrap4j()); + $this->assertFalse($mergedConfig->hasCoverageHtml()); + $this->assertFalse($mergedConfig->hasCoverageOpenClover()); + $this->assertFalse($mergedConfig->hasCoverageText()); + $this->assertFalse($mergedConfig->hasCoverageXml()); + + $this->assertTrue($mergedConfig->hasCoveragePhp()); + $this->assertSame($phpCoverage, $mergedConfig->coveragePhp()); + } + + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/6340')] + public function testIssue6340(): void + { + $fromFile = (new Loader)->load(TEST_FILES_PATH . 'configuration-issue-6340.xml'); + + $this->assertTrue($fromFile->phpunit()->failOnPhpunitDeprecation()); + $this->assertTrue($fromFile->phpunit()->failOnPhpunitNotice()); + $this->assertTrue($fromFile->phpunit()->failOnDeprecation()); + $this->assertTrue($fromFile->phpunit()->failOnNotice()); + $this->assertTrue($fromFile->phpunit()->failOnWarning()); + $this->assertTrue($fromFile->phpunit()->failOnIncomplete()); + $this->assertTrue($fromFile->phpunit()->failOnSkipped()); + + $fromCli = (new Builder)->fromParameters([ + '--do-not-fail-on-phpunit-deprecation', + '--do-not-fail-on-phpunit-notice', + '--do-not-fail-on-deprecation', + '--do-not-fail-on-notice', + '--do-not-fail-on-warning', + '--do-not-fail-on-incomplete', + '--do-not-fail-on-skipped', + ]); + + $this->assertTrue($fromCli->doNotFailOnPhpunitDeprecation()); + $this->assertTrue($fromCli->doNotFailOnPhpunitNotice()); + $this->assertTrue($fromCli->doNotFailOnDeprecation()); + $this->assertTrue($fromCli->doNotFailOnNotice()); + $this->assertTrue($fromCli->doNotFailOnWarning()); + $this->assertTrue($fromCli->doNotFailOnIncomplete()); + $this->assertTrue($fromCli->doNotFailOnSkipped()); + + $mergedConfig = (new Merger)->merge($fromCli, $fromFile); + + $this->assertTrue($mergedConfig->doNotFailOnPhpunitDeprecation()); + $this->assertTrue($mergedConfig->doNotFailOnPhpunitNotice()); + $this->assertTrue($mergedConfig->doNotFailOnDeprecation()); + $this->assertTrue($mergedConfig->doNotFailOnNotice()); + $this->assertTrue($mergedConfig->doNotFailOnWarning()); + $this->assertTrue($mergedConfig->doNotFailOnIncomplete()); + $this->assertTrue($mergedConfig->doNotFailOnSkipped()); + + $this->assertFalse($mergedConfig->displayDetailsOnPhpunitDeprecations()); + $this->assertFalse($mergedConfig->displayDetailsOnPhpunitNotices()); + $this->assertFalse($mergedConfig->displayDetailsOnTestsThatTriggerDeprecations()); + $this->assertFalse($mergedConfig->displayDetailsOnTestsThatTriggerNotices()); + $this->assertFalse($mergedConfig->displayDetailsOnTestsThatTriggerWarnings()); + $this->assertFalse($mergedConfig->displayDetailsOnIncompleteTests()); + $this->assertFalse($mergedConfig->displayDetailsOnSkippedTests()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/ConstantCollectionTest.php b/tests/unit/TextUI/Configuration/Value/ConstantCollectionTest.php new file mode 100644 index 00000000000..d01426fcf8e --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/ConstantCollectionTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ConstantCollection::class)] +#[CoversClass(ConstantCollectionIterator::class)] +#[UsesClass(Constant::class)] +#[Small] +final class ConstantCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = ConstantCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = ConstantCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = ConstantCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): Constant + { + return new Constant('name', 'value'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/ConstantTest.php b/tests/unit/TextUI/Configuration/Value/ConstantTest.php new file mode 100644 index 00000000000..96ec65acc76 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/ConstantTest.php @@ -0,0 +1,30 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Constant::class)] +#[Small] +final class ConstantTest extends TestCase +{ + public function testHasName(): void + { + $this->assertSame('name', new Constant('name', 'value')->name()); + } + + public function testHasValue(): void + { + $this->assertSame('value', new Constant('name', 'value')->value()); + $this->assertSame(true, new Constant('name', true)->value()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/DirectoryCollectionTest.php b/tests/unit/TextUI/Configuration/Value/DirectoryCollectionTest.php new file mode 100644 index 00000000000..6031909affd --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/DirectoryCollectionTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(DirectoryCollection::class)] +#[CoversClass(DirectoryCollectionIterator::class)] +#[UsesClass(Directory::class)] +#[Small] +final class DirectoryCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = DirectoryCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = DirectoryCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertFalse($elements->isEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = DirectoryCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): Directory + { + return new Directory('path'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/DirectoryTest.php b/tests/unit/TextUI/Configuration/Value/DirectoryTest.php new file mode 100644 index 00000000000..ad66f2040b6 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/DirectoryTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Directory::class)] +#[Small] +final class DirectoryTest extends TestCase +{ + public function testHasPath(): void + { + $path = 'path'; + + $this->assertSame($path, new Directory($path)->path()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapCollectionTest.php b/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapCollectionTest.php new file mode 100644 index 00000000000..c5aec047506 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapCollectionTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExtensionBootstrapCollection::class)] +#[CoversClass(ExtensionBootstrapCollectionIterator::class)] +#[UsesClass(ExtensionBootstrap::class)] +#[Small] +final class ExtensionBootstrapCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = ExtensionBootstrapCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = ExtensionBootstrapCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): ExtensionBootstrap + { + return new ExtensionBootstrap('ClassName', []); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapTest.php b/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapTest.php new file mode 100644 index 00000000000..81296710a86 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/ExtensionBootstrapTest.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExtensionBootstrap::class)] +#[Small] +final class ExtensionBootstrapTest extends TestCase +{ + public function testHasClassName(): void + { + $className = 'ClassName'; + + $this->assertSame($className, new ExtensionBootstrap($className, [])->className()); + } + + public function testHasParameters(): void + { + $parameters = ['foo' => 'bar']; + + $this->assertSame($parameters, new ExtensionBootstrap('ClassName', $parameters)->parameters()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/FileCollectionTest.php b/tests/unit/TextUI/Configuration/Value/FileCollectionTest.php new file mode 100644 index 00000000000..e79ef89df39 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/FileCollectionTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(FileCollection::class)] +#[CoversClass(FileCollectionIterator::class)] +#[UsesClass(File::class)] +#[Small] +final class FileCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = FileCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = FileCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertTrue($elements->notEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = FileCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): File + { + return new File('path'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/FileTest.php b/tests/unit/TextUI/Configuration/Value/FileTest.php new file mode 100644 index 00000000000..1defb5d8cb1 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/FileTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(File::class)] +#[Small] +final class FileTest extends TestCase +{ + public function testHasPath(): void + { + $path = 'path'; + + $this->assertSame($path, new File($path)->path()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/FilterDirectoryCollectionTest.php b/tests/unit/TextUI/Configuration/Value/FilterDirectoryCollectionTest.php new file mode 100644 index 00000000000..5f96b7958fb --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/FilterDirectoryCollectionTest.php @@ -0,0 +1,55 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(FilterDirectoryCollection::class)] +#[CoversClass(FilterDirectoryCollectionIterator::class)] +#[UsesClass(FilterDirectory::class)] +#[Small] +final class FilterDirectoryCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = FilterDirectoryCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = FilterDirectoryCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertTrue($elements->notEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = FilterDirectoryCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): FilterDirectory + { + return new FilterDirectory('path', 'prefix', 'suffix'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/FilterDirectoryTest.php b/tests/unit/TextUI/Configuration/Value/FilterDirectoryTest.php new file mode 100644 index 00000000000..8611a5b0b31 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/FilterDirectoryTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(FilterDirectory::class)] +#[Small] +final class FilterDirectoryTest extends TestCase +{ + public function testHasPath(): void + { + $path = 'path'; + + $this->assertSame($path, new FilterDirectory($path, 'prefix', 'suffix')->path()); + } + + public function testHasPrefix(): void + { + $prefix = 'prefix'; + + $this->assertSame($prefix, new FilterDirectory('path', $prefix, 'suffix')->prefix()); + } + + public function testHasSuffix(): void + { + $suffix = 'suffix'; + + $this->assertSame($suffix, new FilterDirectory('path', 'prefix', $suffix)->suffix()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/GroupCollectionTest.php b/tests/unit/TextUI/Configuration/Value/GroupCollectionTest.php new file mode 100644 index 00000000000..32a229526ef --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/GroupCollectionTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(GroupCollection::class)] +#[CoversClass(GroupCollectionIterator::class)] +#[UsesClass(Group::class)] +#[Small] +final class GroupCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = GroupCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + $this->assertFalse($elements->isEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = GroupCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + public function testCanBeRepresentedAsArrayOfStrings(): void + { + $elements = GroupCollection::fromArray( + [ + new Group('foo'), + new Group('bar'), + ], + ); + + $this->assertSame(['foo', 'bar'], $elements->asArrayOfStrings()); + } + + private function element(): Group + { + return new Group('name'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/GroupTest.php b/tests/unit/TextUI/Configuration/Value/GroupTest.php new file mode 100644 index 00000000000..5dc506eaac0 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/GroupTest.php @@ -0,0 +1,26 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Group::class)] +#[Small] +final class GroupTest extends TestCase +{ + public function testHasPath(): void + { + $name = 'name'; + + $this->assertSame($name, new Group($name)->name()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/IniSettingCollectionTest.php b/tests/unit/TextUI/Configuration/Value/IniSettingCollectionTest.php new file mode 100644 index 00000000000..11c5f9a6fe8 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/IniSettingCollectionTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IniSettingCollection::class)] +#[CoversClass(IniSettingCollectionIterator::class)] +#[UsesClass(IniSetting::class)] +#[Small] +final class IniSettingCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = IniSettingCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = IniSettingCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = IniSettingCollection::fromArray([$element]); + + foreach ($elements as $index => $_IniSetting) { + $this->assertSame(0, $index); + $this->assertSame($element, $_IniSetting); + } + } + + private function element(): IniSetting + { + return new IniSetting('name', 'value'); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/IniSettingTest.php b/tests/unit/TextUI/Configuration/Value/IniSettingTest.php new file mode 100644 index 00000000000..a4d93f259de --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/IniSettingTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(IniSetting::class)] +#[Small] +final class IniSettingTest extends TestCase +{ + public function testHasName(): void + { + $this->assertSame('name', new IniSetting('name', 'value')->name()); + } + + public function testHasValue(): void + { + $this->assertSame('value', new IniSetting('name', 'value')->value()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/PhpTest.php b/tests/unit/TextUI/Configuration/Value/PhpTest.php new file mode 100644 index 00000000000..db139ffedfd --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/PhpTest.php @@ -0,0 +1,116 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Php::class)] +#[Small] +final class PhpTest extends TestCase +{ + private readonly DirectoryCollection $includePaths; + private readonly IniSettingCollection $iniSettings; + private readonly ConstantCollection $constants; + private readonly VariableCollection $globalVariables; + private readonly VariableCollection $envVariables; + private readonly VariableCollection $postVariables; + private readonly VariableCollection $getVariables; + private readonly VariableCollection $cookieVariables; + private readonly VariableCollection $serverVariables; + private readonly VariableCollection $filesVariables; + private readonly VariableCollection $requestVariables; + private readonly Php $fixture; + + protected function setUp(): void + { + $this->includePaths = DirectoryCollection::fromArray([]); + $this->iniSettings = IniSettingCollection::fromArray([]); + $this->constants = ConstantCollection::fromArray([]); + $this->globalVariables = VariableCollection::fromArray([]); + $this->envVariables = VariableCollection::fromArray([]); + $this->postVariables = VariableCollection::fromArray([]); + $this->getVariables = VariableCollection::fromArray([]); + $this->cookieVariables = VariableCollection::fromArray([]); + $this->serverVariables = VariableCollection::fromArray([]); + $this->filesVariables = VariableCollection::fromArray([]); + $this->requestVariables = VariableCollection::fromArray([]); + + $this->fixture = new Php( + $this->includePaths, + $this->iniSettings, + $this->constants, + $this->globalVariables, + $this->envVariables, + $this->postVariables, + $this->getVariables, + $this->cookieVariables, + $this->serverVariables, + $this->filesVariables, + $this->requestVariables, + ); + } + + public function testHasIncludePaths(): void + { + $this->assertSame($this->includePaths, $this->fixture->includePaths()); + } + + public function testHasIniSettings(): void + { + $this->assertSame($this->iniSettings, $this->fixture->iniSettings()); + } + + public function testHasConstants(): void + { + $this->assertSame($this->constants, $this->fixture->constants()); + } + + public function testHasGlobalVariables(): void + { + $this->assertSame($this->globalVariables, $this->fixture->globalVariables()); + } + + public function testHasEnvVariables(): void + { + $this->assertSame($this->envVariables, $this->fixture->envVariables()); + } + + public function testHasPostVariables(): void + { + $this->assertSame($this->postVariables, $this->fixture->postVariables()); + } + + public function testHasGetVariables(): void + { + $this->assertSame($this->getVariables, $this->fixture->getVariables()); + } + + public function testHasCookieVariables(): void + { + $this->assertSame($this->cookieVariables, $this->fixture->cookieVariables()); + } + + public function testHasServerVariables(): void + { + $this->assertSame($this->serverVariables, $this->fixture->serverVariables()); + } + + public function testHasFilesVariables(): void + { + $this->assertSame($this->filesVariables, $this->fixture->filesVariables()); + } + + public function testHasRequestVariables(): void + { + $this->assertSame($this->requestVariables, $this->fixture->requestVariables()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/SourceTest.php b/tests/unit/TextUI/Configuration/Value/SourceTest.php new file mode 100644 index 00000000000..cda89543505 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/SourceTest.php @@ -0,0 +1,831 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Source::class)] +#[UsesClass(FilterDirectory::class)] +#[UsesClass(FilterDirectoryCollection::class)] +#[UsesClass(FilterDirectoryCollectionIterator::class)] +#[UsesClass(File::class)] +#[UsesClass(FileCollection::class)] +#[UsesClass(FileCollectionIterator::class)] +#[Small] +final class SourceTest extends TestCase +{ + public function testHasIncludeDirectories(): void + { + $includeDirectories = FilterDirectoryCollection::fromArray([]); + + $source = new Source( + null, + false, + $includeDirectories, + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertSame($includeDirectories, $source->includeDirectories()); + } + + public function testHasIncludeFiles(): void + { + $includeFiles = FileCollection::fromArray([]); + + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + $includeFiles, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertSame($includeFiles, $source->includeFiles()); + } + + public function testHasExcludeDirectories(): void + { + $excludeDirectories = FilterDirectoryCollection::fromArray([]); + + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + $excludeDirectories, + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertSame($excludeDirectories, $source->excludeDirectories()); + } + + public function testHasExcludeFiles(): void + { + $excludeFiles = FileCollection::fromArray([]); + + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + $excludeFiles, + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertSame($excludeFiles, $source->excludeFiles()); + } + + public function testMayHaveBaseline(): void + { + $baseline = 'baseline.xml'; + + $source = new Source( + $baseline, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertSame($baseline, $source->baseline()); + $this->assertTrue($source->hasBaseline()); + $this->assertTrue($source->useBaseline()); + } + + public function testMayNotHaveBaseline(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->hasBaseline()); + $this->assertFalse($source->useBaseline()); + + $this->expectException(NoBaselineException::class); + + $source->baseline(); + } + + public function testRestrictionOfNoticesMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->restrictNotices()); + } + + public function testRestrictionOfNoticesMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + true, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->restrictNotices()); + } + + public function testRestrictionOfWarningsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->restrictWarnings()); + } + + public function testRestrictionOfWarningsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + true, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->restrictWarnings()); + } + + public function testIgnoringOfSuppressedDeprecationsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfDeprecations()); + } + + public function testIgnoringOfSuppressedDeprecationsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + true, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfDeprecations()); + } + + public function testIgnoringOfSuppressedPhpDeprecationsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfPhpDeprecations()); + } + + public function testIgnoringOfSuppressedPhpDeprecationsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + true, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfPhpDeprecations()); + } + + public function testIgnoringOfSuppressedErrorsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfErrors()); + } + + public function testIgnoringOfSuppressedErrorsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + true, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfErrors()); + } + + public function testIgnoringOfSuppressedNoticesMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfNotices()); + } + + public function testIgnoringOfSuppressedNoticesMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + true, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfNotices()); + } + + public function testIgnoringOfSuppressedPhpNoticesMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfPhpNotices()); + } + + public function testIgnoringOfSuppressedPhpNoticesMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + true, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfPhpNotices()); + } + + public function testIgnoringOfSuppressedWarningsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfWarnings()); + } + + public function testIgnoringOfSuppressedWarningsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + true, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfWarnings()); + } + + public function testIgnoringOfSuppressedPhpWarningsMayBeDisabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->ignoreSuppressionOfPhpWarnings()); + } + + public function testIgnoringOfSuppressedPhpWarningsMayBeEnabled(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + true, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->ignoreSuppressionOfPhpWarnings()); + } + + public function testMayBeEmpty(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertFalse($source->notEmpty()); + } + + public function testMayNotBeEmpty(): void + { + $source = new Source( + null, + false, + FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + 'path', + 'prefix', + 'suffix', + ), + ], + ), + FileCollection::fromArray([]), + FilterDirectoryCollection::fromArray([]), + FileCollection::fromArray([]), + false, + false, + false, + false, + false, + false, + false, + false, + false, + [ + 'functions' => [], + 'methods' => [], + ], + false, + false, + false, + ); + + $this->assertTrue($source->notEmpty()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php new file mode 100644 index 00000000000..ea1423c572b --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryCollectionTest.php @@ -0,0 +1,63 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(TestDirectoryCollection::class)] +#[CoversClass(TestDirectoryCollectionIterator::class)] +#[UsesClass(TestDirectory::class)] +#[Small] +final class TestDirectoryCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = TestDirectoryCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = TestDirectoryCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertFalse($elements->isEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = TestDirectoryCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): TestDirectory + { + return new TestDirectory( + 'path', + 'prefix', + 'suffix', + '8.2.0', + new VersionComparisonOperator('>='), + [], + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php new file mode 100644 index 00000000000..040c5e316fd --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestDirectoryTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(TestDirectory::class)] +#[Small] +final class TestDirectoryTest extends TestCase +{ + public function testHasPath(): void + { + $this->assertSame('path', $this->fixture()->path()); + } + + public function testHasPrefix(): void + { + $this->assertSame('prefix', $this->fixture()->prefix()); + } + + public function testHasSuffix(): void + { + $this->assertSame('suffix', $this->fixture()->suffix()); + } + + public function testHasPhpVersion(): void + { + $this->assertSame('8.2.0', $this->fixture()->phpVersion()); + } + + public function testHasPhpVersionOperator(): void + { + $this->assertSame('>=', $this->fixture()->phpVersionOperator()->asString()); + } + + public function testHasGroups(): void + { + $this->assertSame(['group'], $this->fixture()->groups()); + } + + private function fixture(): TestDirectory + { + return new TestDirectory( + 'path', + 'prefix', + 'suffix', + '8.2.0', + new VersionComparisonOperator('>='), + ['group'], + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php new file mode 100644 index 00000000000..7691b4cb2d2 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestFileCollectionTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(TestFileCollection::class)] +#[CoversClass(TestFileCollectionIterator::class)] +#[UsesClass(TestFile::class)] +#[Small] +final class TestFileCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = TestFileCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = TestFileCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertFalse($elements->isEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = TestFileCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): TestFile + { + return new TestFile( + 'path', + '8.2.0', + new VersionComparisonOperator('>='), + [], + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestFileTest.php b/tests/unit/TextUI/Configuration/Value/TestFileTest.php new file mode 100644 index 00000000000..63b2914f005 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestFileTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\VersionComparisonOperator; + +#[CoversClass(TestFile::class)] +#[Small] +final class TestFileTest extends TestCase +{ + public function testHasPath(): void + { + $this->assertSame('path', $this->fixture()->path()); + } + + public function testHasPhpVersion(): void + { + $this->assertSame('8.2.0', $this->fixture()->phpVersion()); + } + + public function testHasPhpVersionOperator(): void + { + $this->assertSame('>=', $this->fixture()->phpVersionOperator()->asString()); + } + + public function testHasGroups(): void + { + $this->assertSame(['group'], $this->fixture()->groups()); + } + + private function fixture(): TestFile + { + return new TestFile( + 'path', + '8.2.0', + new VersionComparisonOperator('>='), + ['group'], + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestSuiteCollectionTest.php b/tests/unit/TextUI/Configuration/Value/TestSuiteCollectionTest.php new file mode 100644 index 00000000000..e3dd3644c3c --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestSuiteCollectionTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestSuiteCollection::class)] +#[CoversClass(TestSuiteCollectionIterator::class)] +#[UsesClass(TestSuite::class)] +#[Small] +final class TestSuiteCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = TestSuiteCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = TestSuiteCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + $this->assertFalse($elements->isEmpty()); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = TestSuiteCollection::fromArray([$element]); + + foreach ($elements as $index => $_constant) { + $this->assertSame(0, $index); + $this->assertSame($element, $_constant); + } + } + + private function element(): TestSuite + { + return new TestSuite( + 'name', + TestDirectoryCollection::fromArray([]), + TestFileCollection::fromArray([]), + FileCollection::fromArray([]), + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/TestSuiteTest.php b/tests/unit/TextUI/Configuration/Value/TestSuiteTest.php new file mode 100644 index 00000000000..6c417fa8297 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/TestSuiteTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(TestSuite::class)] +#[Small] +final class TestSuiteTest extends TestCase +{ + private readonly string $name; + private readonly TestDirectoryCollection $directories; + private readonly TestFileCollection $files; + private readonly FileCollection $excludedFiles; + private readonly TestSuite $fixture; + + protected function setUp(): void + { + $this->name = 'name'; + $this->directories = TestDirectoryCollection::fromArray([]); + $this->files = TestFileCollection::fromArray([]); + $this->excludedFiles = FileCollection::fromArray([]); + + $this->fixture = new TestSuite( + $this->name, + $this->directories, + $this->files, + $this->excludedFiles, + ); + } + + public function testHasName(): void + { + $this->assertSame($this->name, $this->fixture->name()); + } + + public function testDirectories(): void + { + $this->assertSame($this->directories, $this->fixture->directories()); + } + + public function testHasFiles(): void + { + $this->assertSame($this->files, $this->fixture->files()); + } + + public function testHasExcludedFiles(): void + { + $this->assertSame($this->excludedFiles, $this->fixture->exclude()); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/VariableCollectionTest.php b/tests/unit/TextUI/Configuration/Value/VariableCollectionTest.php new file mode 100644 index 00000000000..ad2f686e173 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/VariableCollectionTest.php @@ -0,0 +1,54 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\TestCase; + +#[CoversClass(VariableCollection::class)] +#[CoversClass(VariableCollectionIterator::class)] +#[UsesClass(Variable::class)] +#[Small] +final class VariableCollectionTest extends TestCase +{ + public function testIsCreatedFromArray(): void + { + $element = $this->element(); + $elements = VariableCollection::fromArray([$element]); + + $this->assertSame([$element], $elements->asArray()); + } + + public function testIsCountable(): void + { + $element = $this->element(); + $elements = VariableCollection::fromArray([$element]); + + $this->assertCount(1, $elements); + } + + public function testIsIterable(): void + { + $element = $this->element(); + $elements = VariableCollection::fromArray([$element]); + + foreach ($elements as $index => $_Variable) { + $this->assertSame(0, $index); + $this->assertSame($element, $_Variable); + } + } + + private function element(): Variable + { + return new Variable('name', 'value', false); + } +} diff --git a/tests/unit/TextUI/Configuration/Value/VariableTest.php b/tests/unit/TextUI/Configuration/Value/VariableTest.php new file mode 100644 index 00000000000..6981aa28c61 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Value/VariableTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Variable::class)] +#[Small] +final class VariableTest extends TestCase +{ + public function testHasName(): void + { + $this->assertSame('name', new Variable('name', 'value', false)->name()); + } + + public function testHasValue(): void + { + $this->assertSame('value', new Variable('name', 'value', false)->value()); + } + + public function testValueCanBeForced(): void + { + $this->assertFalse(new Variable('name', 'value', false)->force()); + $this->assertTrue(new Variable('name', 'value', true)->force()); + } +} diff --git a/tests/unit/TextUI/Configuration/Xml/GeneratorTest.php b/tests/unit/TextUI/Configuration/Xml/GeneratorTest.php new file mode 100644 index 00000000000..375596e5797 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Xml/GeneratorTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Generator::class)] +#[Small] +final class GeneratorTest extends TestCase +{ + public function testGeneratesConfigurationCorrectly(): void + { + $generator = new Generator; + + $this->assertEquals( + ' + + + + tests + + + + + + src + + + +', + $generator->generateDefaultConfiguration( + 'https://schema.phpunit.de/X.Y/phpunit.xsd', + 'vendor/autoload.php', + 'tests', + 'src', + '.phpunit.cache', + ), + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Xml/LoaderTest.php b/tests/unit/TextUI/Configuration/Xml/LoaderTest.php new file mode 100644 index 00000000000..cecb5a77e95 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Xml/LoaderTest.php @@ -0,0 +1,435 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use const PHP_VERSION; +use function file_put_contents; +use function iterator_to_array; +use function realpath; +use function sys_get_temp_dir; +use function uniqid; +use function unlink; +use PHPUnit\Framework\Attributes\CoversNamespace; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\TestSuiteSorter; +use PHPUnit\TextUI\Configuration\Configuration; +use SebastianBergmann\CodeCoverage\Report\Html\Colors; +use SebastianBergmann\CodeCoverage\Report\Thresholds; + +#[CoversNamespace('PHPUnit\TextUI\XmlConfiguration')] +#[Medium] +final class LoaderTest extends TestCase +{ + public static function configurationRootOptionsProvider(): array + { + return [ + 'executionOrder default' => ['executionOrder', 'default', TestSuiteSorter::ORDER_DEFAULT], + 'executionOrder random' => ['executionOrder', 'random', TestSuiteSorter::ORDER_RANDOMIZED], + 'executionOrder reverse' => ['executionOrder', 'reverse', TestSuiteSorter::ORDER_REVERSED], + 'executionOrder size' => ['executionOrder', 'size', TestSuiteSorter::ORDER_SIZE], + 'cacheDirectory absolute path' => ['cacheDirectory', '/path/to/cache', '/path/to/cache'], + 'cacheResult=false' => ['cacheResult', 'false', false], + 'cacheResult=true' => ['cacheResult', 'true', true], + 'columns' => ['columns', 'max', 'max'], + 'stopOnFailure' => ['stopOnFailure', 'true', true], + 'stopOnWarning' => ['stopOnWarning', 'true', true], + 'stopOnIncomplete' => ['stopOnIncomplete', 'true', true], + 'stopOnRisky' => ['stopOnRisky', 'true', true], + 'stopOnSkipped' => ['stopOnSkipped', 'true', true], + 'failOnEmptyTestSuite' => ['failOnEmptyTestSuite', 'true', true], + 'failOnWarning' => ['failOnWarning', 'true', true], + 'failOnRisky' => ['failOnRisky', 'true', true], + 'processIsolation' => ['processIsolation', 'true', true], + 'reverseDefectList' => ['reverseDefectList', 'true', true], + ]; + } + + public function testExceptionIsThrownForNotExistingConfigurationFile(): void + { + $this->expectException(Exception::class); + + /* @noinspection UnusedFunctionResultInspection */ + $this->configuration('not_existing_file.xml'); + } + + public function testShouldReadColorsWhenTrueInConfigurationFile(): void + { + $phpunit = $this->configuration('configuration.colors.true.xml')->phpunit(); + + $this->assertEquals(Configuration::COLOR_AUTO, $phpunit->colors()); + } + + public function testShouldReadColorsWhenFalseInConfigurationFile(): void + { + $phpunit = $this->configuration('configuration.colors.false.xml')->phpunit(); + + $this->assertEquals(Configuration::COLOR_NEVER, $phpunit->colors()); + } + + public function testShouldReadColorsWhenEmptyInConfigurationFile(): void + { + $phpunit = $this->configuration('configuration.colors.empty.xml')->phpunit(); + + $this->assertEquals(Configuration::COLOR_NEVER, $phpunit->colors()); + } + + public function testShouldReadColorsWhenInvalidInConfigurationFile(): void + { + $phpunit = $this->configuration('configuration.colors.invalid.xml')->phpunit(); + + $this->assertEquals(Configuration::COLOR_NEVER, $phpunit->colors()); + } + + public function testInvalidConfigurationGeneratesValidationErrors(): void + { + $configuration = $this->configuration('configuration.colors.invalid.xml'); + + $this->assertTrue($configuration->hasValidationErrors()); + } + + public function testShouldUseDefaultValuesForInvalidIntegers(): void + { + $phpunit = $this->configuration('configuration.columns.default.xml')->phpunit(); + + $this->assertEquals(80, $phpunit->columns()); + } + + #[DataProvider('configurationRootOptionsProvider')] + public function testShouldParseXmlConfigurationRootAttributes(string $optionName, string $optionValue, bool|int|string $expected): void + { + $tmpFilename = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'phpunit.' . $optionName . uniqid('', true) . '.xml'; + $xml = "" . PHP_EOL; + file_put_contents($tmpFilename, $xml); + + $configuration = (new Loader)->load($tmpFilename); + + $this->assertFalse($configuration->hasValidationErrors()); + + $this->assertEquals($expected, $configuration->phpunit()->{$optionName}()); + + @unlink($tmpFilename); + } + + public function testShouldParseXmlConfigurationExecutionOrderCombined(): void + { + $tmpFilename = sys_get_temp_dir() . DIRECTORY_SEPARATOR . 'phpunit.' . uniqid('', true) . '.xml'; + $xml = "" . PHP_EOL; + file_put_contents($tmpFilename, $xml); + + $configuration = (new Loader)->load($tmpFilename); + + $this->assertFalse($configuration->hasValidationErrors()); + + $this->assertTrue($configuration->phpunit()->defectsFirst()); + $this->assertTrue($configuration->phpunit()->resolveDependencies()); + + @unlink($tmpFilename); + } + + public function testSourceConfigurationIsReadCorrectly(): void + { + $source = $this->configuration('configuration_codecoverage.xml')->source(); + + $this->assertTrue($source->hasBaseline()); + $this->assertSame(realpath(__DIR__ . '/../../../../_files') . DIRECTORY_SEPARATOR . '.phpunit/baseline.xml', $source->baseline()); + + $directory = iterator_to_array($source->includeDirectories(), false)[0]; + + $this->assertSame('/path/to/files', $directory->path()); + $this->assertSame('', $directory->prefix()); + $this->assertSame('.php', $directory->suffix()); + + $file = iterator_to_array($source->includeFiles(), false)[0]; + $this->assertSame('/path/to/file', $file->path()); + + $file = iterator_to_array($source->includeFiles(), false)[1]; + $this->assertSame('/path/to/file', $file->path()); + + $directory = iterator_to_array($source->excludeDirectories(), false)[0]; + $this->assertSame('/path/to/files', $directory->path()); + $this->assertSame('', $directory->prefix()); + $this->assertSame('.php', $directory->suffix()); + + $file = iterator_to_array($source->excludeFiles(), false)[0]; + $this->assertSame('/path/to/file', $file->path()); + + $this->assertSame( + [ + 'functions' => [ + 'PHPUnit\TestFixture\DeprecationTrigger\trigger_deprecation', + ], + 'methods' => [ + 'PHPUnit\TestFixture\DeprecationTrigger\DeprecationTrigger::triggerDeprecation', + ], + ], + $source->deprecationTriggers(), + ); + + $this->assertTrue($source->ignoreSelfDeprecations()); + $this->assertTrue($source->ignoreDirectDeprecations()); + $this->assertTrue($source->ignoreIndirectDeprecations()); + } + + public function testCodeCoverageConfigurationIsReadCorrectly(): void + { + $codeCoverage = $this->configuration('configuration_codecoverage.xml')->codeCoverage(); + + $this->assertTrue($codeCoverage->pathCoverage()); + $this->assertTrue($codeCoverage->includeUncoveredFiles()); + $this->assertTrue($codeCoverage->ignoreDeprecatedCodeUnits()); + $this->assertTrue($codeCoverage->disableCodeCoverageIgnore()); + + $this->assertTrue($codeCoverage->hasClover()); + $this->assertSame(TEST_FILES_PATH . 'clover.xml', $codeCoverage->clover()->target()->path()); + + $this->assertTrue($codeCoverage->hasOpenClover()); + $this->assertSame(TEST_FILES_PATH . 'openclover.xml', $codeCoverage->openClover()->target()->path()); + + $this->assertTrue($codeCoverage->hasCobertura()); + $this->assertSame(TEST_FILES_PATH . 'cobertura.xml', $codeCoverage->cobertura()->target()->path()); + + $this->assertTrue($codeCoverage->hasCrap4j()); + $this->assertSame(TEST_FILES_PATH . 'crap4j.xml', $codeCoverage->crap4j()->target()->path()); + + $defaultColors = Colors::default(); + $defaultThresholds = Thresholds::default(); + + $this->assertTrue($codeCoverage->hasHtml()); + $this->assertSame(TEST_FILES_PATH . 'coverage', $codeCoverage->html()->target()->path()); + $this->assertSame($defaultThresholds->lowUpperBound(), $codeCoverage->html()->lowUpperBound()); + $this->assertSame($defaultThresholds->highLowerBound(), $codeCoverage->html()->highLowerBound()); + $this->assertSame($defaultColors->successLow(), $codeCoverage->html()->colorSuccessLow()); + $this->assertSame($defaultColors->successMedium(), $codeCoverage->html()->colorSuccessMedium()); + $this->assertSame($defaultColors->successHigh(), $codeCoverage->html()->colorSuccessHigh()); + $this->assertSame($defaultColors->warning(), $codeCoverage->html()->colorWarning()); + $this->assertSame($defaultColors->danger(), $codeCoverage->html()->colorDanger()); + $this->assertFalse($codeCoverage->html()->hasCustomCssFile()); + + $this->assertTrue($codeCoverage->hasPhp()); + $this->assertSame(TEST_FILES_PATH . 'coverage.php', $codeCoverage->php()->target()->path()); + + $this->assertTrue($codeCoverage->hasText()); + $this->assertSame(TEST_FILES_PATH . 'coverage.txt', $codeCoverage->text()->target()->path()); + $this->assertFalse($codeCoverage->text()->showUncoveredFiles()); + $this->assertTrue($codeCoverage->text()->showOnlySummary()); + + $this->assertTrue($codeCoverage->hasXml()); + $this->assertSame(TEST_FILES_PATH . 'coverage', $codeCoverage->xml()->target()->path()); + } + + public function testGroupConfigurationIsReadCorrectly(): void + { + $groups = $this->configuration('configuration.xml')->groups(); + + $this->assertTrue($groups->hasInclude()); + $this->assertSame(['name'], $groups->include()->asArrayOfStrings()); + + $this->assertTrue($groups->hasExclude()); + $this->assertSame(['name'], $groups->exclude()->asArrayOfStrings()); + } + + public function testExtensionConfigurationIsReadCorrectly(): void + { + $extensions = $this->configuration('configuration.xml')->extensions(); + + $this->assertCount(1, $extensions->asArray()); + + $extension = $extensions->asArray()[0]; + + $this->assertSame('MyExtension', $extension->className()); + + $this->assertSame( + [ + 'foo' => 'bar', + 'bar' => 'foo', + ], + $extension->parameters(), + ); + } + + public function testLoggingConfigurationIsReadCorrectly(): void + { + $logging = $this->configuration('configuration_logging.xml')->logging(); + + $this->assertTrue($logging->hasJunit()); + $this->assertSame(TEST_FILES_PATH . 'junit.xml', $logging->junit()->target()->path()); + + $this->assertTrue($logging->hasOtr()); + $this->assertSame(TEST_FILES_PATH . 'otr.xml', $logging->otr()->target()->path()); + $this->assertTrue($logging->otr()->includeGitInformation()); + + $this->assertTrue($logging->hasTeamCity()); + $this->assertSame(TEST_FILES_PATH . 'teamcity.txt', $logging->teamCity()->target()->path()); + + $this->assertTrue($logging->hasTestDoxHtml()); + $this->assertSame(TEST_FILES_PATH . 'testdox.html', $logging->testDoxHtml()->target()->path()); + + $this->assertTrue($logging->hasTestDoxText()); + $this->assertSame(TEST_FILES_PATH . 'testdox.txt', $logging->testDoxText()->target()->path()); + } + + public function testPHPConfigurationIsReadCorrectly(): void + { + $php = $this->configuration('configuration.xml')->php(); + + $this->assertSame(TEST_FILES_PATH . '.', $php->includePaths()->asArray()[0]->path()); + $this->assertSame('/path/to/lib', $php->includePaths()->asArray()[1]->path()); + + $this->assertSame('foo', $php->iniSettings()->asArray()[0]->name()); + $this->assertSame('bar', $php->iniSettings()->asArray()[0]->value()); + $this->assertSame('highlight.keyword', $php->iniSettings()->asArray()[1]->name()); + $this->assertSame('#123456', $php->iniSettings()->asArray()[1]->value()); + + $this->assertSame('FOO', $php->constants()->asArray()[0]->name()); + $this->assertFalse($php->constants()->asArray()[0]->value()); + $this->assertSame('BAR', $php->constants()->asArray()[1]->name()); + $this->assertTrue($php->constants()->asArray()[1]->value()); + + $this->assertSame('foo', $php->globalVariables()->asArray()[0]->name()); + $this->assertFalse($php->globalVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->postVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->postVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->getVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->getVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->cookieVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->cookieVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->serverVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->serverVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->filesVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->filesVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->requestVariables()->asArray()[0]->name()); + $this->assertSame('bar', $php->requestVariables()->asArray()[0]->value()); + + $this->assertSame('foo', $php->envVariables()->asArray()[0]->name()); + $this->assertTrue($php->envVariables()->asArray()[0]->value()); + $this->assertFalse($php->envVariables()->asArray()[0]->force()); + + $this->assertSame('foo_force', $php->envVariables()->asArray()[1]->name()); + $this->assertSame('forced', $php->envVariables()->asArray()[1]->value()); + $this->assertTrue($php->envVariables()->asArray()[1]->force()); + + $this->assertSame('bar', $php->envVariables()->asArray()[2]->name()); + $this->assertSame('true', $php->envVariables()->asArray()[2]->value()); + $this->assertFalse($php->envVariables()->asArray()[2]->force()); + } + + public function testPHPUnitConfigurationIsReadCorrectly(): void + { + $phpunit = $this->configuration('configuration.xml')->phpunit(); + + $this->assertTrue($phpunit->backupGlobals()); + $this->assertFalse($phpunit->backupStaticProperties()); + $this->assertFalse($phpunit->beStrictAboutChangesToGlobalState()); + $this->assertSame('/path/to/bootstrap.php', $phpunit->bootstrap()); + $this->assertSame(80, $phpunit->columns()); + $this->assertSame('never', $phpunit->colors()); + $this->assertFalse($phpunit->stderr()); + $this->assertFalse($phpunit->requireCoverageMetadata()); + $this->assertFalse($phpunit->stopOnFailure()); + $this->assertFalse($phpunit->stopOnWarning()); + $this->assertFalse($phpunit->beStrictAboutTestsThatDoNotTestAnything()); + $this->assertFalse($phpunit->beStrictAboutCoverageMetadata()); + $this->assertFalse($phpunit->beStrictAboutOutputDuringTests()); + $this->assertSame(123, $phpunit->defaultTimeLimit()); + $this->assertFalse($phpunit->enforceTimeLimit()); + $this->assertSame('/tmp', $phpunit->extensionsDirectory()); + $this->assertSame('My Test Suite', $phpunit->defaultTestSuite()); + $this->assertSame(1, $phpunit->timeoutForSmallTests()); + $this->assertSame(10, $phpunit->timeoutForMediumTests()); + $this->assertSame(60, $phpunit->timeoutForLargeTests()); + $this->assertFalse($phpunit->failOnEmptyTestSuite()); + $this->assertFalse($phpunit->failOnIncomplete()); + $this->assertFalse($phpunit->failOnRisky()); + $this->assertFalse($phpunit->failOnSkipped()); + $this->assertFalse($phpunit->failOnWarning()); + $this->assertSame(TestSuiteSorter::ORDER_DEFAULT, $phpunit->executionOrder()); + $this->assertFalse($phpunit->defectsFirst()); + $this->assertTrue($phpunit->resolveDependencies()); + $this->assertTrue($phpunit->controlGarbageCollector()); + $this->assertSame(1000, $phpunit->numberOfTestsBeforeGarbageCollection()); + $this->assertSame(10, $phpunit->shortenArraysForExportThreshold()); + } + + public function test_TestDox_configuration_is_parsed_correctly(): void + { + $configuration = $this->configuration('configuration_testdox.xml')->phpunit(); + + $this->assertTrue($configuration->testdoxPrinter()); + $this->assertTrue($configuration->testdoxPrinterSummary()); + } + + public function testConfigurationForSingleTestSuiteCanBeLoaded(): void + { + $testSuites = $this->configuration('configuration_testsuite.xml')->testSuite(); + + $this->assertCount(1, $testSuites); + + $first = $testSuites->asArray()[0]; + $this->assertSame('first', $first->name()); + $this->assertCount(1, $first->directories()); + $this->assertSame(TEST_FILES_PATH . 'tests/first', $first->directories()->asArray()[0]->path()); + $this->assertSame('', $first->directories()->asArray()[0]->prefix()); + $this->assertSame('Test.php', $first->directories()->asArray()[0]->suffix()); + $this->assertSame(PHP_VERSION, $first->directories()->asArray()[0]->phpVersion()); + $this->assertSame('>=', $first->directories()->asArray()[0]->phpVersionOperator()->asString()); + $this->assertCount(0, $first->files()); + $this->assertCount(0, $first->exclude()); + } + + public function testConfigurationForMultipleTestSuitesCanBeLoaded(): void + { + $testSuites = $this->configuration('configuration_testsuites.xml')->testSuite(); + + $this->assertCount(2, $testSuites); + + $first = $testSuites->asArray()[0]; + $this->assertSame('first', $first->name()); + $this->assertCount(1, $first->directories()); + $this->assertSame(TEST_FILES_PATH . 'tests/first', $first->directories()->asArray()[0]->path()); + $this->assertSame('', $first->directories()->asArray()[0]->prefix()); + $this->assertSame('Test.php', $first->directories()->asArray()[0]->suffix()); + $this->assertSame(PHP_VERSION, $first->directories()->asArray()[0]->phpVersion()); + $this->assertSame('>=', $first->directories()->asArray()[0]->phpVersionOperator()->asString()); + $this->assertCount(0, $first->files()); + $this->assertCount(0, $first->exclude()); + $this->assertSame(['foo'], $first->directories()->asArray()[0]->groups()); + + $second = $testSuites->asArray()[1]; + $this->assertSame('second', $second->name()); + $this->assertSame(TEST_FILES_PATH . 'tests/second', $second->directories()->asArray()[0]->path()); + $this->assertSame('test', $second->directories()->asArray()[0]->prefix()); + $this->assertSame('.phpt', $second->directories()->asArray()[0]->suffix()); + $this->assertSame('1.2.3', $second->directories()->asArray()[0]->phpVersion()); + $this->assertSame('==', $second->directories()->asArray()[0]->phpVersionOperator()->asString()); + $this->assertCount(1, $second->files()); + $this->assertSame(TEST_FILES_PATH . 'tests/file.php', $second->files()->asArray()[0]->path()); + $this->assertSame('4.5.6', $second->files()->asArray()[0]->phpVersion()); + $this->assertSame('!=', $second->files()->asArray()[0]->phpVersionOperator()->asString()); + $this->assertCount(1, $second->exclude()); + $this->assertSame(TEST_FILES_PATH . 'tests/second/_files', $second->exclude()->asArray()[0]->path()); + $this->assertSame(['bar'], $second->directories()->asArray()[0]->groups()); + $this->assertSame(['baz'], $second->files()->asArray()[0]->groups()); + } + + private function configuration(string $filename): LoadedFromFileConfiguration + { + return (new Loader)->load(TEST_FILES_PATH . $filename); + } +} diff --git a/tests/unit/TextUI/Configuration/Xml/MigratorTest.php b/tests/unit/TextUI/Configuration/Xml/MigratorTest.php new file mode 100644 index 00000000000..dd65d966921 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Xml/MigratorTest.php @@ -0,0 +1,56 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\TestCase; +use PHPUnit\Util\Xml\Loader as XmlLoader; + +final class MigratorTest extends TestCase +{ + public static function provider(): array + { + return [ + 'PHPUnit 9.2' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-9.2.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-9.2.xml', + ], + 'PHPUnit 9.5' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-9.5.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-9.5.xml', + ], + 'Relative Path' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-relative-schema-path.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-relative-schema-path.xml', + ], + 'No Schema Location' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-no-schema-location.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-no-schema-location.xml', + ], + 'Issue 5859' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-issue-5859.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-issue-5859.xml', + ], + 'Issue 6087' => [ + __DIR__ . '/../../../../_files/XmlConfigurationMigration/output-issue-6087.xml', + __DIR__ . '/../../../../_files/XmlConfigurationMigration/input-issue-6087.xml', + ], + ]; + } + + #[DataProvider('provider')] + public function testCanMigrateConfigurationFileThatValidatesAgainstPreviousSchema(string $output, string $input): void + { + $this->assertEquals( + (new XmlLoader)->loadFile($output), + (new XmlLoader)->load((new Migrator)->migrate($input)), + ); + } +} diff --git a/tests/unit/TextUI/Configuration/Xml/SchemaFinderTest.php b/tests/unit/TextUI/Configuration/Xml/SchemaFinderTest.php new file mode 100644 index 00000000000..6b4f703a19f --- /dev/null +++ b/tests/unit/TextUI/Configuration/Xml/SchemaFinderTest.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function count; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Version; + +#[CoversClass(SchemaFinder::class)] +#[Small] +final class SchemaFinderTest extends TestCase +{ + public function testListsAvailableSchemas(): void + { + $schemas = (new SchemaFinder)->available(); + + $this->assertSame((new Version)->series(), $schemas[0]); + $this->assertSame('8.5', $schemas[count($schemas) - 1]); + } + + public function testFindsExistingSchema(): void + { + $this->assertFileExists((new SchemaFinder)->find((new Version)->series())); + } + + public function testDoesNotFindNonExistentSchema(): void + { + $this->expectException(CannotFindSchemaException::class); + + (new SchemaFinder)->find('0.0'); + } +} diff --git a/tests/unit/TextUI/Configuration/Xml/ValidatorTest.php b/tests/unit/TextUI/Configuration/Xml/ValidatorTest.php new file mode 100644 index 00000000000..1d58e7b7ee2 --- /dev/null +++ b/tests/unit/TextUI/Configuration/Xml/ValidatorTest.php @@ -0,0 +1,50 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\XmlConfiguration; + +use function file_get_contents; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\Version; +use PHPUnit\Util\Xml\Loader; + +#[CoversClass(Validator::class)] +#[CoversClass(ValidationResult::class)] +#[Small] +final class ValidatorTest extends TestCase +{ + public function testValidatesValidXmlFile(): void + { + $result = (new Validator)->validate( + (new Loader)->loadFile(__DIR__ . '/../../../../../phpunit.xml'), + (new SchemaFinder)->find(Version::series()), + ); + + $this->assertFalse($result->hasValidationErrors()); + $this->assertSame('', $result->asString()); + } + + public function testDoesNotValidateInvalidXmlFile(): void + { + $result = (new Validator)->validate( + (new Loader)->loadFile( + __DIR__ . '/../../../../end-to-end/migration/_files/possibility-to-migrate-from-92-is-detected/phpunit.xml', + ), + (new SchemaFinder)->find(Version::series()), + ); + + $this->assertTrue($result->hasValidationErrors()); + $this->assertStringEqualsStringIgnoringLineEndings( + file_get_contents(__DIR__ . '/../../../../_files/invalid-configuration.txt'), + $result->asString(), + ); + } +} diff --git a/tests/unit/TextUI/Output/Default/DefaultPrinterTest.php b/tests/unit/TextUI/Output/Default/DefaultPrinterTest.php new file mode 100644 index 00000000000..d843dc379c9 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/DefaultPrinterTest.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\CannotOpenSocketException; +use PHPUnit\TextUI\InvalidSocketException; +use PHPUnit\TextUI\Output\DefaultPrinter; + +#[CoversClass(DefaultPrinter::class)] +#[Medium] +final class DefaultPrinterTest extends TestCase +{ + public static function providePrinter(): array + { + $data = [ + 'standard output' => [DefaultPrinter::standardOutput()], + 'standard error' => [DefaultPrinter::standardError()], + ]; + + try { + $data['socket'] = [DefaultPrinter::from('socket://www.example.com:80')]; + } catch (CannotOpenSocketException $e) { + } + + return $data; + } + + #[DataProvider('providePrinter')] + public function testFlush(DefaultPrinter $printer): void + { + $printer->flush(); + $this->expectOutputString(''); + } + + public function testInvalidSocket(): void + { + $this->expectException(InvalidSocketException::class); + DefaultPrinter::from('socket://hostname:port:wrong'); + } +} diff --git a/tests/unit/TextUI/Output/Default/ResultPrinterTest.php b/tests/unit/TextUI/Output/Default/ResultPrinterTest.php new file mode 100644 index 00000000000..ac8465043c1 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/ResultPrinterTest.php @@ -0,0 +1,587 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use const PHP_OS; +use function hrtime; +use function stripos; +use Exception; +use PHPUnit\Event\Code\TestDoxBuilder; +use PHPUnit\Event\Code\TestMethod; +use PHPUnit\Event\Code\ThrowableBuilder; +use PHPUnit\Event\Telemetry\Duration; +use PHPUnit\Event\Telemetry\GarbageCollectorStatus; +use PHPUnit\Event\Telemetry\HRTime; +use PHPUnit\Event\Telemetry\Info; +use PHPUnit\Event\Telemetry\MemoryUsage; +use PHPUnit\Event\Telemetry\Snapshot; +use PHPUnit\Event\Test\BeforeFirstTestMethodErrored; +use PHPUnit\Event\Test\ConsideredRisky; +use PHPUnit\Event\Test\Errored; +use PHPUnit\Event\Test\Failed; +use PHPUnit\Event\Test\MarkedIncomplete; +use PHPUnit\Event\Test\PhpunitDeprecationTriggered; +use PHPUnit\Event\Test\PhpunitErrorTriggered; +use PHPUnit\Event\Test\PhpunitNoticeTriggered; +use PHPUnit\Event\Test\PhpunitWarningTriggered; +use PHPUnit\Event\Test\Skipped as TestSkipped; +use PHPUnit\Event\TestData\TestDataCollection; +use PHPUnit\Event\TestRunner\DeprecationTriggered as TestRunnerDeprecationTriggered; +use PHPUnit\Event\TestRunner\NoticeTriggered as TestRunnerNoticeTriggered; +use PHPUnit\Event\TestRunner\WarningTriggered as TestRunnerWarningTriggered; +use PHPUnit\Event\TestSuite\Skipped as TestSuiteSkipped; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\IncompleteTestError; +use PHPUnit\Framework\TestCase; +use PHPUnit\Metadata\MetadataCollection; +use PHPUnit\TestRunner\TestResult\Issues\Issue; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; + +#[CoversClass(ResultPrinter::class)] +#[Medium] +final class ResultPrinterTest extends TestCase +{ + /** + * @return array + */ + public static function provider(): array + { + return [ + 'no tests' => [ + 'no_tests.txt', + self::createTestResult( + numberOfTestsRun: 0, + ), + ], + + 'successful test without issues' => [ + 'successful_test_without_issues.txt', + self::createTestResult(), + ], + + 'errored test' => [ + 'errored_test.txt', + self::createTestResult( + testErroredEvents: [ + self::erroredTest(), + ], + ), + ], + + 'failed test' => [ + 'failed_test.txt', + self::createTestResult( + testFailedEvents: [ + self::failedTest(), + ], + ), + ], + + 'incomplete test' => [ + 'incomplete_test.txt', + self::createTestResult( + testMarkedIncompleteEvents: [ + new MarkedIncomplete( + self::telemetryInfo(), + self::testMethod(), + ThrowableBuilder::from(new IncompleteTestError('message')), + ), + ], + ), + ], + + 'skipped test' => [ + 'skipped_test.txt', + self::createTestResult( + testSkippedEvents: [ + new TestSkipped( + self::telemetryInfo(), + self::testMethod(), + 'message', + ), + ], + ), + ], + + 'risky test with single-line message' => [ + 'risky_test_single_line_message.txt', + self::createTestResult( + testConsideredRiskyEvents: [ + 'Foo::testBar' => [ + self::riskyTest('message'), + ], + ], + ), + ], + + 'risky test with multiple reasons with single-line messages' => [ + 'risky_test_with_multiple_reasons_with_single_line_messages.txt', + self::createTestResult( + testConsideredRiskyEvents: [ + 'Foo::testBar' => [ + self::riskyTest('message'), + self::riskyTest('message'), + ], + ], + ), + ], + + 'risky test with multiple reasons with multi-line messages' => [ + (stripos(PHP_OS, 'WIN') === 0) ? + 'risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt' : + 'risky_test_with_multiple_reasons_with_multi_line_messages.txt', + self::createTestResult( + testConsideredRiskyEvents: [ + 'Foo::testBar' => [ + self::riskyTest("message\nmessage\nmessage"), + self::riskyTest("message\nmessage\nmessage"), + ], + ], + ), + ], + + 'errored test that is risky' => [ + 'errored_test_that_is_risky.txt', + self::createTestResult( + testErroredEvents: [ + self::erroredTest(), + ], + testConsideredRiskyEvents: [ + 'Foo::testBar' => [ + self::riskyTest('message'), + ], + ], + ), + ], + + 'failed test that is risky' => [ + 'failed_test_that_is_risky.txt', + self::createTestResult( + testFailedEvents: [ + self::failedTest(), + ], + testConsideredRiskyEvents: [ + 'Foo::testBar' => [ + self::riskyTest('message'), + ], + ], + ), + ], + + 'successful test that triggers deprecation (do not display stack trace)' => [ + 'successful_test_with_deprecation.txt', + self::createTestResult( + deprecations: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers deprecation (display stack trace)' => [ + 'successful_test_with_deprecation_with_stack_trace.txt', + self::createTestResult( + deprecations: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + '/path/to/file.php:1234', + ), + ], + ), + true, + ], + + 'successful test that triggers PHP deprecation' => [ + 'successful_test_with_php_deprecation.txt', + self::createTestResult( + phpDeprecations: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + Issue::from( + 'Foo.php', + 2, + 'another message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers the same PHP deprecation multiple times' => [ + 'successful_test_with_php_deprecation_multiple.txt', + self::createTestResult( + phpDeprecations: self::samePhpDeprecationsTriggeredTwice(), + ), + ], + + 'successful test that triggers PHPUnit deprecation' => [ + 'successful_test_with_phpunit_deprecation.txt', + self::createTestResult( + testTriggeredPhpunitDeprecationEvents: [ + 'Foo::testBar' => [ + new PhpunitDeprecationTriggered( + self::telemetryInfo(), + self::testMethod(), + 'message', + ), + ], + ], + testRunnerTriggeredDeprecationEvents: [ + new TestRunnerDeprecationTriggered( + self::telemetryInfo(), + 'message', + ), + ], + ), + ], + + 'successful test that triggers error' => [ + 'successful_test_with_error.txt', + self::createTestResult( + errors: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers notice' => [ + 'successful_test_with_notice.txt', + self::createTestResult( + notices: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers PHP notice' => [ + 'successful_test_with_php_notice.txt', + self::createTestResult( + phpNotices: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers warning' => [ + 'successful_test_with_warning.txt', + self::createTestResult( + warnings: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'successful test that triggers PHP warning' => [ + 'successful_test_with_php_warning.txt', + self::createTestResult( + phpWarnings: [ + Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ), + ], + ), + ], + + 'test that triggers PHPUnit error' => [ + 'test_with_phpunit_error.txt', + self::createTestResult( + numberOfTests: 0, + numberOfTestsRun: 0, + numberOfAssertions: 0, + testTriggeredPhpunitErrorEvents: [ + 'Foo::testBar' => [ + new PhpunitErrorTriggered( + self::telemetryInfo(), + self::testMethod(), + 'message', + ), + ], + ], + ), + ], + + 'successful test and PHPUnit test runner notice' => [ + 'successful_test_and_phpunit_test_runner_notice.txt', + self::createTestResult( + testRunnerTriggeredNoticeEvents: [ + new TestRunnerNoticeTriggered( + self::telemetryInfo(), + 'message', + ), + ], + ), + ], + + 'successful test that triggers PHPUnit notice' => [ + 'successful_test_with_phpunit_notice.txt', + self::createTestResult( + testTriggeredPhpunitNoticeEvents: [ + 'Foo::testBar' => [ + new PhpunitNoticeTriggered( + self::telemetryInfo(), + self::testMethod(), + 'message', + ), + ], + ], + ), + ], + + 'successful test that triggers PHPUnit warning' => [ + 'successful_test_with_phpunit_warning.txt', + self::createTestResult( + testTriggeredPhpunitWarningEvents: [ + 'Foo::testBar' => [ + new PhpunitWarningTriggered( + self::telemetryInfo(), + self::testMethod(), + 'message', + false, + ), + ], + ], + ), + ], + + 'successful test that triggers baseline-ignored issue' => [ + 'successful_test_with_baseline_ignored_issue.txt', + self::createTestResult( + numberOfIssuesIgnoredByBaseline: 1, + ), + ], + + 'successful test that triggers baseline-ignored issues' => [ + 'successful_test_with_baseline_ignored_issues.txt', + self::createTestResult( + numberOfIssuesIgnoredByBaseline: 2, + ), + ], + ]; + } + + #[DataProvider('provider')] + public function testPrintsExpectedOutputForTestResultObject(string $expectationFile, TestResult $result, bool $stackTraceForDeprecations = false): void + { + $printer = $this->printer(); + + $resultPrinter = new ResultPrinter( + $printer, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + true, + false, + ); + + $resultPrinter->print($result, $stackTraceForDeprecations); + + /* @noinspection PhpPossiblePolymorphicInvocationInspection */ + $this->assertStringMatchesFormatFile( + __DIR__ . '/expectations/result/' . $expectationFile, + $printer->buffer(), + ); + } + + private function printer(): Printer + { + return new class implements Printer + { + private string $buffer = ''; + + public function print(string $buffer): void + { + $this->buffer .= $buffer; + } + + public function flush(): void + { + } + + public function buffer(): string + { + return $this->buffer; + } + }; + } + + /** + * @param list $testErroredEvents + * @param list $testFailedEvents + * @param array> $testConsideredRiskyEvents + * @param list $testSuiteSkippedEvents + * @param list $testSkippedEvents + * @param list $testMarkedIncompleteEvents + * @param list $deprecations + * @param list $phpDeprecations + * @param array> $testTriggeredPhpunitDeprecationEvents + * @param list $errors + * @param list $notices + * @param list $phpNotices + * @param list $warnings + * @param list $phpWarnings + * @param array> $testTriggeredPhpunitErrorEvents + * @param array> $testTriggeredPhpunitNoticeEvents + * @param array> $testTriggeredPhpunitWarningEvents + * @param list $testRunnerTriggeredDeprecationEvents + * @param list $testRunnerTriggeredNoticeEvents + * @param list $testRunnerTriggeredWarningEvents + */ + private static function createTestResult(int $numberOfTests = 1, int $numberOfTestsRun = 1, int $numberOfAssertions = 1, array $testErroredEvents = [], array $testFailedEvents = [], array $testConsideredRiskyEvents = [], array $testSuiteSkippedEvents = [], array $testSkippedEvents = [], array $testMarkedIncompleteEvents = [], array $deprecations = [], array $phpDeprecations = [], array $testTriggeredPhpunitDeprecationEvents = [], array $errors = [], array $notices = [], array $phpNotices = [], array $warnings = [], array $phpWarnings = [], array $testTriggeredPhpunitErrorEvents = [], array $testTriggeredPhpunitNoticeEvents = [], array $testTriggeredPhpunitWarningEvents = [], array $testRunnerTriggeredDeprecationEvents = [], array $testRunnerTriggeredNoticeEvents = [], array $testRunnerTriggeredWarningEvents = [], int $numberOfIssuesIgnoredByBaseline = 0): TestResult + { + return new TestResult( + $numberOfTests, + $numberOfTestsRun, + $numberOfAssertions, + $testErroredEvents, + $testFailedEvents, + $testConsideredRiskyEvents, + $testSuiteSkippedEvents, + $testSkippedEvents, + $testMarkedIncompleteEvents, + $testTriggeredPhpunitDeprecationEvents, + $testTriggeredPhpunitErrorEvents, + $testTriggeredPhpunitNoticeEvents, + $testTriggeredPhpunitWarningEvents, + $testRunnerTriggeredDeprecationEvents, + $testRunnerTriggeredNoticeEvents, + $testRunnerTriggeredWarningEvents, + $errors, + $deprecations, + $notices, + $warnings, + $phpDeprecations, + $phpNotices, + $phpWarnings, + $numberOfIssuesIgnoredByBaseline, + ); + } + + private static function erroredTest(): Errored + { + return new Errored( + self::telemetryInfo(), + self::testMethod(), + ThrowableBuilder::from(new Exception('message')), + ); + } + + private static function failedTest(): Failed + { + return new Failed( + self::telemetryInfo(), + self::testMethod(), + ThrowableBuilder::from( + new ExpectationFailedException( + 'Failed asserting that false is true.', + ), + ), + null, + ); + } + + private static function riskyTest(string $message): ConsideredRisky + { + return new ConsideredRisky( + self::telemetryInfo(), + self::testMethod(), + $message, + ); + } + + private static function testMethod(): TestMethod + { + return new TestMethod( + 'FooTest', + 'testBar', + 'FooTest.php', + 1, + TestDoxBuilder::fromClassNameAndMethodName('Foo', 'bar'), + MetadataCollection::fromArray([]), + TestDataCollection::fromArray([]), + ); + } + + private static function telemetryInfo(): Info + { + return new Info( + new Snapshot( + HRTime::fromSecondsAndNanoseconds(...hrtime(false)), + MemoryUsage::fromBytes(1000), + MemoryUsage::fromBytes(2000), + new GarbageCollectorStatus(0, 0, 0, 0, 0.0, 0.0, 0.0, 0.0, false, false, false, 0), + ), + Duration::fromSecondsAndNanoseconds(123, 456), + MemoryUsage::fromBytes(2000), + Duration::fromSecondsAndNanoseconds(234, 567), + MemoryUsage::fromBytes(3000), + ); + } + + private static function samePhpDeprecationsTriggeredTwice(): array + { + $issue = Issue::from( + 'Foo.php', + 1, + 'message', + self::testMethod(), + ); + + $issue->triggeredBy(self::testMethod()); + + return [$issue]; + } +} diff --git a/tests/unit/TextUI/Output/Default/SummaryPrinterTest.php b/tests/unit/TextUI/Output/Default/SummaryPrinterTest.php new file mode 100644 index 00000000000..2cb087238df --- /dev/null +++ b/tests/unit/TextUI/Output/Default/SummaryPrinterTest.php @@ -0,0 +1,82 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Output\Default; + +use const PHP_OS_FAMILY; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProviderExternal; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestRunner\TestResult\TestResult; +use PHPUnit\TextUI\Output\Printer; +use PHPUnit\TextUI\Output\SummaryPrinter; + +#[CoversClass(SummaryPrinter::class)] +#[Medium] +final class SummaryPrinterTest extends TestCase +{ + #[DataProviderExternal(ResultPrinterTest::class, 'provider', false)] + public function testPrintsExpectedOutputForTestResultObject(string $expectationFile, TestResult $result): void + { + $printer = $this->printer(); + + $summaryPrinter = new SummaryPrinter($printer, false); + + $summaryPrinter->print($result); + + /* @noinspection PhpPossiblePolymorphicInvocationInspection */ + $this->assertStringMatchesFormatFile( + __DIR__ . '/expectations/summary/' . $expectationFile, + $printer->buffer(), + ); + } + + #[DataProviderExternal(ResultPrinterTest::class, 'provider', false)] + public function testPrintsExpectedColouredOutputForTestResultObject(string $expectationFile, TestResult $result): void + { + if (PHP_OS_FAMILY === 'Windows') { + $this->markTestSkipped('Cannot test this behaviour on Windows'); + } + + $printer = $this->printer(); + + $summaryPrinter = new SummaryPrinter($printer, true); + + $summaryPrinter->print($result); + + /* @noinspection PhpPossiblePolymorphicInvocationInspection */ + $this->assertStringMatchesFormatFile( + __DIR__ . '/expectations/summary-coloured/' . $expectationFile, + $printer->buffer(), + ); + } + + private function printer(): Printer + { + return new class implements Printer + { + private string $buffer = ''; + + public function print(string $buffer): void + { + $this->buffer .= $buffer; + } + + public function flush(): void + { + } + + public function buffer(): string + { + return $this->buffer; + } + }; + } +} diff --git a/tests/unit/TextUI/Output/Default/expectations/result/errored_test.txt b/tests/unit/TextUI/Output/Default/expectations/result/errored_test.txt new file mode 100644 index 00000000000..adab017ac7c --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/errored_test.txt @@ -0,0 +1,6 @@ +There was 1 error: + +1) FooTest::testBar +Exception: message + +%A diff --git a/tests/unit/TextUI/Output/Default/expectations/result/errored_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/result/errored_test_that_is_risky.txt new file mode 100644 index 00000000000..00e82fd2d09 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/errored_test_that_is_risky.txt @@ -0,0 +1,15 @@ +There was 1 error: + +1) FooTest::testBar +Exception: message + +%A + +-- + +There was 1 risky test: + +1) FooTest::testBar +message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/failed_test.txt b/tests/unit/TextUI/Output/Default/expectations/result/failed_test.txt new file mode 100644 index 00000000000..4c2af2d945b --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/failed_test.txt @@ -0,0 +1,6 @@ +There was 1 failure: + +1) FooTest::testBar +Failed asserting that false is true. + +%A diff --git a/tests/unit/TextUI/Output/Default/expectations/result/failed_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/result/failed_test_that_is_risky.txt new file mode 100644 index 00000000000..54a8f601353 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/failed_test_that_is_risky.txt @@ -0,0 +1,15 @@ +There was 1 failure: + +1) FooTest::testBar +Failed asserting that false is true. + +%A + +-- + +There was 1 risky test: + +1) FooTest::testBar +message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/incomplete_test.txt b/tests/unit/TextUI/Output/Default/expectations/result/incomplete_test.txt new file mode 100644 index 00000000000..80cf7d89810 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/incomplete_test.txt @@ -0,0 +1,6 @@ +There was 1 incomplete test: + +1) FooTest::testBar +message + +%A diff --git a/tests/unit/TextUI/Output/Default/expectations/result/no_tests.txt b/tests/unit/TextUI/Output/Default/expectations/result/no_tests.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/TextUI/Output/Default/expectations/result/risky_test_single_line_message.txt b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_single_line_message.txt new file mode 100644 index 00000000000..0e520846c1a --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_single_line_message.txt @@ -0,0 +1,6 @@ +There was 1 risky test: + +1) FooTest::testBar +message + +FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages.txt new file mode 100644 index 00000000000..3fd85f81546 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages.txt @@ -0,0 +1,12 @@ +There was 1 risky test: + +1) FooTest::testBar +* message + message + message + +* message + message + message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt new file mode 100644 index 00000000000..d4e06f9ad29 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt @@ -0,0 +1,12 @@ +There was 1 risky test: + +1) FooTest::testBar +* message +message +message + +* message +message +message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_single_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_single_line_messages.txt new file mode 100644 index 00000000000..f9cfca51031 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/risky_test_with_multiple_reasons_with_single_line_messages.txt @@ -0,0 +1,8 @@ +There was 1 risky test: + +1) FooTest::testBar +* message + +* message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/skipped_test.txt b/tests/unit/TextUI/Output/Default/expectations/result/skipped_test.txt new file mode 100644 index 00000000000..5dc6b2186fb --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/skipped_test.txt @@ -0,0 +1,4 @@ +There was 1 skipped test: + +1) FooTest::testBar +message diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_and_phpunit_test_runner_notice.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_and_phpunit_test_runner_notice.txt new file mode 100644 index 00000000000..5d62e6f6a10 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_and_phpunit_test_runner_notice.txt @@ -0,0 +1,3 @@ +There was 1 PHPUnit test runner notice: + +1) message diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_baseline_ignored_issue.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_baseline_ignored_issue.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_baseline_ignored_issues.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_baseline_ignored_issues.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation.txt new file mode 100644 index 00000000000..57d0c61a164 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation.txt @@ -0,0 +1,9 @@ +1 test triggered 1 deprecation: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation_with_stack_trace.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation_with_stack_trace.txt new file mode 100644 index 00000000000..346a84ea8e2 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_deprecation_with_stack_trace.txt @@ -0,0 +1,11 @@ +1 test triggered 1 deprecation: + +1) Foo.php:1 +message + +/path/to/file.php:1234 + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_error.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_error.txt new file mode 100644 index 00000000000..590e2f2a37f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_error.txt @@ -0,0 +1,9 @@ +1 test triggered 1 error: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_notice.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_notice.txt new file mode 100644 index 00000000000..ea9652becfc --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_notice.txt @@ -0,0 +1,9 @@ +1 test triggered 1 notice: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation.txt new file mode 100644 index 00000000000..812178e3681 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation.txt @@ -0,0 +1,17 @@ +1 test triggered 2 PHP deprecations: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 + +2) Foo.php:2 +another message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation_multiple.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation_multiple.txt new file mode 100644 index 00000000000..60ba73e2e7b --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_deprecation_multiple.txt @@ -0,0 +1,9 @@ +1 test triggered 1 PHP deprecation: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar (2 times) + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_notice.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_notice.txt new file mode 100644 index 00000000000..218f5a62cb1 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_notice.txt @@ -0,0 +1,9 @@ +1 test triggered 1 PHP notice: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_warning.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_warning.txt new file mode 100644 index 00000000000..2cc3c2d58ac --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_php_warning.txt @@ -0,0 +1,9 @@ +1 test triggered 1 PHP warning: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_deprecation.txt new file mode 100644 index 00000000000..39ca95251a0 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_deprecation.txt @@ -0,0 +1,12 @@ +There was 1 PHPUnit test runner deprecation: + +1) message + +-- + +1 test triggered 1 PHPUnit deprecation: + +1) FooTest::testBar +message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_notice.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_notice.txt new file mode 100644 index 00000000000..9a555cb975f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_notice.txt @@ -0,0 +1,6 @@ +1 test triggered 1 PHPUnit notice: + +1) FooTest::testBar +message + +FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_warning.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_warning.txt new file mode 100644 index 00000000000..ae7719307bc --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_phpunit_warning.txt @@ -0,0 +1,6 @@ +1 test triggered 1 PHPUnit warning: + +1) FooTest::testBar +message + +%s:%i diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_warning.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_warning.txt new file mode 100644 index 00000000000..406d3cc0792 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_with_warning.txt @@ -0,0 +1,9 @@ +1 test triggered 1 warning: + +1) Foo.php:1 +message + +Triggered by: + +* FooTest::testBar + FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/result/successful_test_without_issues.txt b/tests/unit/TextUI/Output/Default/expectations/result/successful_test_without_issues.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/tests/unit/TextUI/Output/Default/expectations/result/test_with_phpunit_error.txt b/tests/unit/TextUI/Output/Default/expectations/result/test_with_phpunit_error.txt new file mode 100644 index 00000000000..c3bec03d8f3 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/result/test_with_phpunit_error.txt @@ -0,0 +1,6 @@ +There was 1 PHPUnit error: + +1) FooTest::testBar +message + +FooTest.php:1 diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test.txt new file mode 100644 index 00000000000..72823db76a4 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test.txt @@ -0,0 +1,2 @@ +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test_that_is_risky.txt new file mode 100644 index 00000000000..9b6e37cdfd3 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/errored_test_that_is_risky.txt @@ -0,0 +1,2 @@ +ERRORS! +Tests: 1, Assertions: 1, Errors: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test.txt new file mode 100644 index 00000000000..181e8af35c2 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test.txt @@ -0,0 +1,2 @@ +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test_that_is_risky.txt new file mode 100644 index 00000000000..a7dbe5e08d2 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/failed_test_that_is_risky.txt @@ -0,0 +1,2 @@ +FAILURES! +Tests: 1, Assertions: 1, Failures: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/incomplete_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/incomplete_test.txt new file mode 100644 index 00000000000..b1f01090b65 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/incomplete_test.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Incomplete: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/no_tests.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/no_tests.txt new file mode 100644 index 00000000000..d95baa6038f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/no_tests.txt @@ -0,0 +1 @@ +No tests executed! diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_single_line_message.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_single_line_message.txt new file mode 100644 index 00000000000..143fe74bb69 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_single_line_message.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages.txt new file mode 100644 index 00000000000..143fe74bb69 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt new file mode 100644 index 00000000000..2ae6f23df31 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_single_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_single_line_messages.txt new file mode 100644 index 00000000000..143fe74bb69 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/risky_test_with_multiple_reasons_with_single_line_messages.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/skipped_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/skipped_test.txt new file mode 100644 index 00000000000..d1db9ee88f9 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/skipped_test.txt @@ -0,0 +1,2 @@ +OK, but some tests were skipped! +Tests: 1, Assertions: 1, Skipped: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_and_phpunit_test_runner_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_and_phpunit_test_runner_notice.txt new file mode 100644 index 00000000000..e462ec384a9 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_and_phpunit_test_runner_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issue.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issue.txt new file mode 100644 index 00000000000..7a38d34254c --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issue.txt @@ -0,0 +1,3 @@ +OK (1 test, 1 assertion) + +1 issue was ignored by baseline. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issues.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issues.txt new file mode 100644 index 00000000000..5d79463b8a8 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_baseline_ignored_issues.txt @@ -0,0 +1,3 @@ +OK (1 test, 1 assertion) + +2 issues were ignored by baseline. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation.txt new file mode 100644 index 00000000000..16cfe86c139 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation_with_stack_trace.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation_with_stack_trace.txt new file mode 100644 index 00000000000..16cfe86c139 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_deprecation_with_stack_trace.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_error.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_error.txt new file mode 100644 index 00000000000..97e139df0b2 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_error.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_notice.txt new file mode 100644 index 00000000000..48231abcb42 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation.txt new file mode 100644 index 00000000000..4749d0a5411 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 2. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation_multiple.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation_multiple.txt new file mode 100644 index 00000000000..16cfe86c139 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_deprecation_multiple.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_notice.txt new file mode 100644 index 00000000000..48231abcb42 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_warning.txt new file mode 100644 index 00000000000..de9601e6f77 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_php_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_deprecation.txt new file mode 100644 index 00000000000..6ef7ae1a4f7 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 2. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_notice.txt new file mode 100644 index 00000000000..e462ec384a9 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_warning.txt new file mode 100644 index 00000000000..3438c3cc1e6 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_phpunit_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_warning.txt new file mode 100644 index 00000000000..de9601e6f77 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_with_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_without_issues.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_without_issues.txt new file mode 100644 index 00000000000..da9758dd4dc --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/successful_test_without_issues.txt @@ -0,0 +1 @@ +OK (1 test, 1 assertion) diff --git a/tests/unit/TextUI/Output/Default/expectations/summary-coloured/test_with_phpunit_error.txt b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/test_with_phpunit_error.txt new file mode 100644 index 00000000000..d95baa6038f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary-coloured/test_with_phpunit_error.txt @@ -0,0 +1 @@ +No tests executed! diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/errored_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary/errored_test.txt new file mode 100644 index 00000000000..49b585ccfca --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/errored_test.txt @@ -0,0 +1,2 @@ +ERRORS! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/errored_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/summary/errored_test_that_is_risky.txt new file mode 100644 index 00000000000..9c5e0b930b0 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/errored_test_that_is_risky.txt @@ -0,0 +1,2 @@ +ERRORS! +Tests: 1, Assertions: 1, Errors: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/failed_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary/failed_test.txt new file mode 100644 index 00000000000..ce476b0f456 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/failed_test.txt @@ -0,0 +1,2 @@ +FAILURES! +Tests: 1, Assertions: 1, Failures: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/failed_test_that_is_risky.txt b/tests/unit/TextUI/Output/Default/expectations/summary/failed_test_that_is_risky.txt new file mode 100644 index 00000000000..476745183e5 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/failed_test_that_is_risky.txt @@ -0,0 +1,2 @@ +FAILURES! +Tests: 1, Assertions: 1, Failures: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/incomplete_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary/incomplete_test.txt new file mode 100644 index 00000000000..529dd1c69f2 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/incomplete_test.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Incomplete: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/no_tests.txt b/tests/unit/TextUI/Output/Default/expectations/summary/no_tests.txt new file mode 100644 index 00000000000..6cf1a983e2b --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/no_tests.txt @@ -0,0 +1 @@ +No tests executed! diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_single_line_message.txt b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_single_line_message.txt new file mode 100644 index 00000000000..2ae6f23df31 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_single_line_message.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages.txt new file mode 100644 index 00000000000..2ae6f23df31 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt new file mode 100644 index 00000000000..2ae6f23df31 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_multi_line_messages_windows.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_single_line_messages.txt b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_single_line_messages.txt new file mode 100644 index 00000000000..2ae6f23df31 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/risky_test_with_multiple_reasons_with_single_line_messages.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Risky: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/skipped_test.txt b/tests/unit/TextUI/Output/Default/expectations/summary/skipped_test.txt new file mode 100644 index 00000000000..378257774c5 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/skipped_test.txt @@ -0,0 +1,2 @@ +OK, but some tests were skipped! +Tests: 1, Assertions: 1, Skipped: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_and_phpunit_test_runner_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_and_phpunit_test_runner_notice.txt new file mode 100644 index 00000000000..5d8a4fb209f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_and_phpunit_test_runner_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issue.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issue.txt new file mode 100644 index 00000000000..1ba4579e02d --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issue.txt @@ -0,0 +1,3 @@ +OK (1 test, 1 assertion) + +1 issue was ignored by baseline. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issues.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issues.txt new file mode 100644 index 00000000000..cb11847ada7 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_baseline_ignored_issues.txt @@ -0,0 +1,3 @@ +OK (1 test, 1 assertion) + +2 issues were ignored by baseline. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation.txt new file mode 100644 index 00000000000..2501835aa6f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation_with_stack_trace.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation_with_stack_trace.txt new file mode 100644 index 00000000000..2501835aa6f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_deprecation_with_stack_trace.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_error.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_error.txt new file mode 100644 index 00000000000..7485151bd93 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_error.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Errors: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_notice.txt new file mode 100644 index 00000000000..e5e0a403e12 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation.txt new file mode 100644 index 00000000000..952e1f6a996 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 2. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation_multiple.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation_multiple.txt new file mode 100644 index 00000000000..2501835aa6f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_deprecation_multiple.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Deprecations: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_notice.txt new file mode 100644 index 00000000000..e5e0a403e12 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_warning.txt new file mode 100644 index 00000000000..253995cfad4 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_php_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_deprecation.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_deprecation.txt new file mode 100644 index 00000000000..b30542b38c1 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_deprecation.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Deprecations: 2. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_notice.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_notice.txt new file mode 100644 index 00000000000..5d8a4fb209f --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_notice.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Notices: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_warning.txt new file mode 100644 index 00000000000..0edddfe9583 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_phpunit_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, PHPUnit Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_warning.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_warning.txt new file mode 100644 index 00000000000..253995cfad4 --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_with_warning.txt @@ -0,0 +1,2 @@ +OK, but there were issues! +Tests: 1, Assertions: 1, Warnings: 1. diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_without_issues.txt b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_without_issues.txt new file mode 100644 index 00000000000..06c5d69bc2b --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/successful_test_without_issues.txt @@ -0,0 +1 @@ +OK (1 test, 1 assertion) diff --git a/tests/unit/TextUI/Output/Default/expectations/summary/test_with_phpunit_error.txt b/tests/unit/TextUI/Output/Default/expectations/summary/test_with_phpunit_error.txt new file mode 100644 index 00000000000..6cf1a983e2b --- /dev/null +++ b/tests/unit/TextUI/Output/Default/expectations/summary/test_with_phpunit_error.txt @@ -0,0 +1 @@ +No tests executed! diff --git a/tests/unit/TextUI/PhpHandlerTest.php b/tests/unit/TextUI/PhpHandlerTest.php new file mode 100644 index 00000000000..020d80113cd --- /dev/null +++ b/tests/unit/TextUI/PhpHandlerTest.php @@ -0,0 +1,117 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const BAR; +use const FOO; +use const PATH_SEPARATOR; +use function getenv; +use function ini_get; +use function ini_set; +use function putenv; +use PHPUnit\Framework\Attributes\BackupGlobals; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Medium; +use PHPUnit\Framework\Attributes\Ticket; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\XmlConfiguration\Loader; + +#[CoversClass(PhpHandler::class)] +#[Medium] +final class PhpHandlerTest extends TestCase +{ + #[BackupGlobals(true)] + public function testPHPConfigurationIsHandledCorrectly(): void + { + $savedIniHighlightKeyword = ini_get('highlight.keyword'); + + $this->handle(); + + $path = TEST_FILES_PATH . '.' . PATH_SEPARATOR . '/path/to/lib'; + $this->assertStringStartsWith($path, ini_get('include_path')); + $this->assertEquals('#123456', ini_get('highlight.keyword')); + $this->assertFalse(FOO); + $this->assertTrue(BAR); + $this->assertFalse($GLOBALS['foo']); + $this->assertTrue((bool) $_ENV['foo']); + $this->assertEquals(1, getenv('foo')); + $this->assertEquals('bar', $_POST['foo']); + $this->assertEquals('bar', $_GET['foo']); + $this->assertEquals('bar', $_COOKIE['foo']); + $this->assertEquals('bar', $_SERVER['foo']); + $this->assertEquals('bar', $_FILES['foo']); + $this->assertEquals('bar', $_REQUEST['foo']); + + ini_set('highlight.keyword', $savedIniHighlightKeyword); + } + + #[BackupGlobals(true)] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/1181')] + public function testHandlePHPConfigurationDoesNotOverwriteExistingEnvArrayVariables(): void + { + $_ENV['foo'] = false; + + $this->handle(); + + $this->assertFalse($_ENV['foo']); + $this->assertEquals('forced', getenv('foo_force')); + } + + #[BackupGlobals(true)] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/1181')] + public function testHandlePHPConfigurationDoesNotOverwriteVariablesFromPutEnv(): void + { + $backupFoo = getenv('foo'); + + putenv('foo=putenv'); + + $this->handle(); + + $this->assertEquals('putenv', $_ENV['foo']); + $this->assertEquals('putenv', getenv('foo')); + + if ($backupFoo === false) { + putenv('foo'); // delete variable from environment + } else { + putenv("foo={$backupFoo}"); + } + } + + #[BackupGlobals(true)] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/1181')] + public function testHandlePHPConfigurationDoesOverwriteVariablesFromPutEnvWhenForced(): void + { + putenv('foo_force=putenv'); + + $this->handle(); + + $this->assertEquals('forced', $_ENV['foo_force']); + $this->assertEquals('forced', getenv('foo_force')); + } + + #[BackupGlobals(true)] + #[Ticket('https://github.com/sebastianbergmann/phpunit/issues/2353')] + public function testHandlePHPConfigurationDoesForceOverwrittenExistingEnvArrayVariables(): void + { + $_ENV['foo_force'] = false; + + $this->handle(); + + $this->assertEquals('forced', $_ENV['foo_force']); + $this->assertEquals('forced', getenv('foo_force')); + } + + private function handle(): void + { + $configuration = (new Loader)->load(TEST_FILES_PATH . 'configuration.xml')->php(); + + (new PhpHandler)->handle($configuration); + } +} diff --git a/tests/unit/TextUI/SourceFilterTest.php b/tests/unit/TextUI/SourceFilterTest.php new file mode 100644 index 00000000000..4b2d4fb9bce --- /dev/null +++ b/tests/unit/TextUI/SourceFilterTest.php @@ -0,0 +1,430 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use function json_encode; +use function sprintf; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(SourceFilter::class)] +#[Small] +final class SourceFilterTest extends AbstractSouceFilterTestCase +{ + public static function provider(): array + { + return [ + 'file included using file' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource(includeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + )), + ], + 'file included using file, but excluded using directory' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeFiles: FileCollection::fromArray([ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ]), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('/a'), + '', + '.php', + ), + ], + ), + ), + ], + 'file included using file, but excluded using file' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + excludeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + ), + ], + 'file included using directory' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', '.php'), + ], + ), + ), + ], + 'file included using directory, but excluded using file' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', '.php'), + ], + ), + excludeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + ), + ], + 'file included using directory, but excluded using directory' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', '.php'), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('/a'), '', '.php'), + ], + ), + ), + ], + 'file included using directory, but wrong suffix' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', 'Foobar.php'), + ], + ), + ), + ], + 'file included using directory, but wrong prefix' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), 'WrongPrefix', '.php'), + ], + ), + ), + ], + 'file included using directory, but not excluded by suffix' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', '.php'), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), '', 'WrongSuffix.php'), + ], + ), + ), + ], + 'file included using directory, but not excluded by prefix' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), 'BadPrefix', '.php'), + ], + ), + ), + ], + 'directory wildcard does not include files at same level' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath(), 'a/*', '.php'), + ], + ), + ), + ], + 'directory wildcard with suffix does not match files' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/Pre*'), '', '.php'), + ], + ), + ), + ], + 'directory wildcard with suffix matches directories' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a*'), '', '.php'), + ], + ), + ), + ], + 'directory wildcard with prefix matches directories' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('*a'), '', '.php'), + ], + ), + ), + ], + 'directory wildcards with prefix and suffix matches directories' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + self::fixturePath('a/c/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('*a/c*'), '', '.php'), + ], + ), + ), + ], + 'directory wildcard includes files' => [ + [ + self::fixturePath('a/c/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/*'), '', '.php'), + ], + ), + ), + ], + 'directory wildcard includes files in sub-directories' => [ + [ + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/*'), '', '.php'), + ], + ), + ), + ], + 'wildcard includes all files' => [ + [ + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('*'), '', '.php'), + ], + ), + ), + ], + 'globstar includes files at globstar\'s level' => [ + [ + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/**'), '', '.php'), + ], + ), + ), + ], + 'globstar includes files at globstar\'s level (2)' => [ + [ + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/c/**'), '', '.php'), + ], + ), + ), + ], + 'globstar includes all files' => [ + [ + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('**'), + '', + '.php', + ), + ], + ), + ), + ], + 'globstar with any single char prefix includes sibling files' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('a/c/Z**'), + '', + '.php', + ), + ], + ), + ), + ], + 'globstar with any more than a single char prefix does not include sibling files' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + self::fixturePath('a/c/PrefixSuffix.php') => false, + self::fixturePath('a/c/d/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('a/c/ZZ**'), + '', + '.php', + ), + ], + ), + ), + ], + 'globstar includes zero directories' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('**/a'), + '', + '.php', + ), + ], + ), + ), + ], + 'globstar with trailing directory' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => false, + self::fixturePath('a/c/PrefixSuffix.php') => false, + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('/a/**/d'), + '', + '.php', + ), + ], + ), + ), + ], + 'question mark' => [ + [ + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => false, + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('a/?/d'), '', '.php'), + ], + ), + ), + ], + 'multiple question marks' => [ + [ + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixSuffix.php') => false, + self::fixturePath('a/c/PrefixSuffix.php') => false, + self::fixturePath('a/PrefixSuffix.php') => false, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory(self::fixturePath('?/?/d'), '', '.php'), + ], + ), + ), + ], + ]; + } + + #[DataProvider('provider')] + public function testDeterminesWhetherFileIsIncluded(array $expectations, Source $source): void + { + foreach ($expectations as $file => $shouldInclude) { + $this->assertFileExists($file); + $this->assertSame( + $shouldInclude, + new SourceFilter((new SourceMapper)->map($source))->includes($file), + sprintf('expected match to return %s for: %s', json_encode($shouldInclude), $file), + ); + } + } +} diff --git a/tests/unit/TextUI/SourceMapperTest.php b/tests/unit/TextUI/SourceMapperTest.php new file mode 100644 index 00000000000..c4cb7387f92 --- /dev/null +++ b/tests/unit/TextUI/SourceMapperTest.php @@ -0,0 +1,352 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\TextUI\Configuration; + +use const PHP_OS_FAMILY; +use Generator; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; + +#[CoversClass(SourceMapper::class)] +#[Small] +final class SourceMapperTest extends AbstractSouceFilterTestCase +{ + public static function provider(): Generator + { + yield 'file included using file' => [ + [ + self::fixturePath('a/PrefixSuffix.php') => true, + ], + self::createSource( + includeFiles: FileCollection::fromArray([ + new File(self::fixturePath('a/PrefixSuffix.php')), + ]), + ), + ]; + + yield 'file included using file, but excluded using directory' => [ + [ + ], + self::createSource( + includeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('/a'), + '', + '.php', + ), + ], + ), + ), + ]; + + yield 'file included using file, but excluded using file' => [ + [ + ], + self::createSource( + includeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + excludeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + ), + ]; + + $fileHiddenOnUnix = self::fixturePath('a/c/.hidden/PrefixSuffix.php'); + + $expectedFiles = [ + $fileHiddenOnUnix => true, + self::fixturePath('a/PrefixSuffix.php') => true, + self::fixturePath('a/c/Prefix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/c/Suffix.php') => true, + self::fixturePath('a/c/d/Prefix.php') => true, + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('a/c/d/Suffix.php') => true, + self::fixturePath('b/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + self::fixturePath('b/e/g/PrefixSuffix.php') => true, + self::fixturePath('b/f/PrefixSuffix.php') => true, + self::fixturePath('b/f/h/PrefixSuffix.php') => true, + ]; + + if (PHP_OS_FAMILY !== 'Windows') { + unset($expectedFiles[$fileHiddenOnUnix]); + } + + yield 'file included using directory' => [ + $expectedFiles, + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ], + ), + ), + ]; + + $expectedFiles = [ + $fileHiddenOnUnix => true, + self::fixturePath('a/c/Prefix.php') => true, + self::fixturePath('a/c/PrefixSuffix.php') => true, + self::fixturePath('a/c/Suffix.php') => true, + self::fixturePath('a/c/d/Prefix.php') => true, + self::fixturePath('a/c/d/PrefixSuffix.php') => true, + self::fixturePath('a/c/d/Suffix.php') => true, + self::fixturePath('b/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + self::fixturePath('b/e/g/PrefixSuffix.php') => true, + self::fixturePath('b/f/PrefixSuffix.php') => true, + self::fixturePath('b/f/h/PrefixSuffix.php') => true, + ]; + + if (PHP_OS_FAMILY !== 'Windows') { + unset($expectedFiles[$fileHiddenOnUnix]); + } + + yield 'file included using directory, but excluded using file' => [ + $expectedFiles, + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ], + ), + excludeFiles: FileCollection::fromArray( + [ + new File(self::fixturePath('/a/PrefixSuffix.php')), + ], + ), + ), + ]; + + yield 'file included using directory, but excluded using directory' => [ + [ + self::fixturePath('b/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixSuffix.php') => true, + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + self::fixturePath('b/e/g/PrefixSuffix.php') => true, + self::fixturePath('b/f/PrefixSuffix.php') => true, + self::fixturePath('b/f/h/PrefixSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath('/a'), + '', + '.php', + ), + ], + ), + ), + ]; + + yield 'files included using directory and prefix' => [ + [ + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + path: self::fixturePath(), + prefix: 'PrefixExample', + suffix: '.php', + ), + ], + ), + ), + ]; + + yield 'files included using directory and suffix' => [ + [ + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + path: self::fixturePath(), + prefix: '', + suffix: 'ExampleSuffix.php', + ), + ], + ), + ), + ]; + + yield 'files excluded using directory and prefix' => [ + [ + self::fixturePath('a/c/Suffix.php') => true, + self::fixturePath('a/c/d/Suffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + path: self::fixturePath(), + prefix: 'Prefix', + suffix: '.php', + ), + ], + ), + ), + ]; + + yield 'files excluded using directory and suffix' => [ + [ + self::fixturePath('a/c/Prefix.php') => true, + self::fixturePath('a/c/d/Prefix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ], + ), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + path: self::fixturePath(), + prefix: '', + suffix: 'Suffix.php', + ), + ], + ), + ), + ]; + + yield 'files included using same directory and different suffixes' => [ + [ + self::fixturePath('a/c/Prefix.php') => true, + self::fixturePath('a/c/d/Prefix.php') => true, + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + '', + 'ExampleSuffix.php', + ), + new FilterDirectory( + self::fixturePath(), + '', + 'Prefix.php', + ), + ], + ), + ), + ]; + + yield 'files included using same directory and different prefixes' => [ + [ + self::fixturePath('a/c/Suffix.php') => true, + self::fixturePath('a/c/d/Suffix.php') => true, + self::fixturePath('b/e/PrefixExampleSuffix.php') => true, + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + 'Suffix', + '.php', + ), + new FilterDirectory( + self::fixturePath(), + 'PrefixExample', + '.php', + ), + ], + ), + ), + ]; + + yield 'files excluded using same directory and different prefixes' => [ + [ + ], + self::createSource( + includeDirectories: FilterDirectoryCollection::fromArray([ + new FilterDirectory( + self::fixturePath(), + '', + '.php', + ), + ]), + excludeDirectories: FilterDirectoryCollection::fromArray( + [ + new FilterDirectory( + self::fixturePath(), + 'Prefix', + '.php', + ), + new FilterDirectory( + self::fixturePath(), + 'Suffix', + '.php', + ), + ], + ), + ), + ]; + } + + #[DataProvider('provider')] + public function testDeterminesWhetherFileIsIncluded(array $expected, Source $source): void + { + $this->assertEquals($expected, (new SourceMapper)->map($source)); + } +} diff --git a/tests/unit/Util/ColorTest.php b/tests/unit/Util/ColorTest.php new file mode 100644 index 00000000000..57700918e9d --- /dev/null +++ b/tests/unit/Util/ColorTest.php @@ -0,0 +1,205 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use const PHP_EOL; +use function str_repeat; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Color::class)] +#[Small] +#[TestDox('Basic ANSI color highlighting support')] +final class ColorTest extends TestCase +{ + public static function colorizeProvider(): array + { + return [ + 'no color' => ['', 'string', 'string'], + 'one color' => ['fg-blue', 'string', "\x1b[34mstring\x1b[0m"], + 'multiple colors' => ['bold,dim,fg-blue,bg-yellow', 'string', "\x1b[1;2;34;43mstring\x1b[0m"], + 'invalid color' => ['fg-invalid', 'some text', 'some text'], + 'valid and invalid colors' => ['fg-invalid,bg-blue', 'some text', "\e[44msome text\e[0m"], + 'empty string' => ['fg-blue', '', ''], + ]; + } + + public static function colorizePathProvider(): array + { + $sep = DIRECTORY_SEPARATOR; + $sepDim = Color::dim($sep); + + return [ + 'null previous path' => [ + null, + $sep . 'php' . $sep . 'unit' . $sep . 'test.phpt', + false, + $sepDim . 'php' . $sepDim . 'unit' . $sepDim . 'test.phpt', + ], + 'empty previous path' => [ + '', + $sep . 'php' . $sep . 'unit' . $sep . 'test.phpt', + false, + $sepDim . 'php' . $sepDim . 'unit' . $sepDim . 'test.phpt', + ], + 'from root' => [ + $sep, + $sep . 'php' . $sep . 'unit' . $sep . 'test.phpt', + false, + $sepDim . 'php' . $sepDim . 'unit' . $sepDim . 'test.phpt', + ], + 'partial part' => [ + $sep . 'php' . $sep, + $sep . 'php' . $sep . 'unit' . $sep . 'test.phpt', + false, + Color::dim($sep . 'php' . $sep) . 'unit' . $sepDim . 'test.phpt', + ], + 'colorize filename' => [ + '', + $sep . '_d-i.r' . $sep . 't-e_s.t.phpt', + true, + $sepDim . '_d-i.r' . $sepDim . 't' . Color::dim('-') . 'e' . Color::dim('_') . 's' . Color::dim('.') . 't' . Color::dim('.phpt'), + ], + ]; + } + + public static function colorizeTextBoxProvider(): array + { + return [ + 'fitting text' => [ + 40, // simulate 40 char wide terminal + 'this is fine' . PHP_EOL . + PHP_EOL . + 'all lines fit nicely' . PHP_EOL . + 'bottom text', + Color::colorize('red', 'this is fine ') . PHP_EOL . + Color::colorize('red', ' ') . PHP_EOL . + Color::colorize('red', 'all lines fit nicely') . PHP_EOL . + Color::colorize('red', 'bottom text '), + ], + 'oversize text' => [ + 20, // simulate 20 char wide terminal + 'this is also fine' . PHP_EOL . + PHP_EOL . + 'the very long lines do not stretch the whole textbox' . PHP_EOL . + 'anymore', + Color::colorize('red', 'this is also fine ') . PHP_EOL . + Color::colorize('red', ' ') . PHP_EOL . + Color::colorize('red', 'the very long lines do not stretch the whole textbox') . PHP_EOL . + Color::colorize('red', 'anymore '), + ], + 'default terminal width cap' => [ + 80, // simulate (default) 80 char wide terminal + str_repeat('.123456789', 8) . PHP_EOL . + 'this is a shorter line', + Color::colorize('red', str_repeat('.123456789', 8)) . PHP_EOL . + Color::colorize('red', 'this is a shorter line '), + ], + ]; + } + + public static function whitespacedStringProvider(): array + { + return [ + ['no-spaces', + 'no-spaces', + ], + [ + ' space invaders ', + "\e[2m·\e[22mspace\e[2m···\e[22minvaders\e[2m·\e[22m", + ], + [ + "\tindent, space and \\n\n\\r\r", + "\e[2m⇥\e[22mindent,\e[2m·\e[22mspace\e[2m·\e[22mand\e[2m·\e[22m\\n\e[2m↵\e[22m\\r\e[2m⟵\e[22m", + ], + ]; + } + + public static function unnamedDataSetProvider(): array + { + return [ + [1], + [2], + ]; + } + + public static function namedDataSetProvider(): array + { + return [ + 'one' => [1], + 'two' => [2], + ]; + } + + #[TestDox('Colorize with $_dataName')] + #[DataProvider('colorizeProvider')] + public function testColorize(string $color, string $buffer, string $expected): void + { + $this->assertSame($expected, Color::colorize($color, $buffer)); + } + + #[TestDox('Colorize path $path after $prevPath')] + #[DataProvider('colorizePathProvider')] + public function testColorizePath(?string $prevPath, string $path, bool $colorizeFilename, string $expected): void + { + $this->assertSame($expected, Color::colorizePath($path, $prevPath, $colorizeFilename)); + } + + #[TestDox('Colorize an autosizing text box')] + #[DataProvider('colorizeTextBoxProvider')] + public function testColorizeTextBox(int $columns, string $buffer, string $expected): void + { + $this->assertSame($expected, Color::colorizeTextBox('red', $buffer, $columns)); + } + + #[TestDox('dim($m) and colorize(\'dim\',$m) return different ANSI codes')] + public function testDimAndColorizeDimAreDifferent(): void + { + $buffer = 'some string'; + $this->assertNotSame(Color::dim($buffer), Color::colorize('dim', $buffer)); + } + + #[DataProvider('whitespacedStringProvider')] + #[TestDox('Visualize all whitespace characters in $actual')] + public function testVisibleWhitespace(string $actual, string $expected): void + { + $this->assertSame($expected, Color::visualizeWhitespace($actual, true)); + } + + #[TestDox('Visualize whitespace but ignore EOL')] + public function testVisualizeWhitespaceButIgnoreEol(): void + { + $string = "line1\nline2\n"; + $this->assertSame($string, Color::visualizeWhitespace($string, false)); + } + + #[DataProvider('unnamedDataSetProvider')] + public function testPrettifyUnnamedDataprovider(int $value): void + { + $this->assertSame($value, $value); + } + + #[DataProvider('namedDataSetProvider')] + public function testPrettifyNamedDataprovider(int $value): void + { + $this->assertSame($value, $value); + } + + #[DataProvider('namedDataSetProvider')] + #[TestDox('TestDox shows name of data set $_dataName with value $value')] + public function testTestdoxDatanameAsParameter(int $value): void + { + $this->assertSame($value, $value); + } +} diff --git a/tests/unit/Util/ExcludeListTest.php b/tests/unit/Util/ExcludeListTest.php new file mode 100644 index 00000000000..31eff0d0d75 --- /dev/null +++ b/tests/unit/Util/ExcludeListTest.php @@ -0,0 +1,66 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function realpath; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\RunTestsInSeparateProcesses; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(ExcludeList::class)] +#[CoversClass(InvalidDirectoryException::class)] +#[Small] +#[RunTestsInSeparateProcesses] +final class ExcludeListTest extends TestCase +{ + public function testIsInitialized(): void + { + $excludeList = new ExcludeList(true); + + $this->assertContains( + realpath(__DIR__ . '/../../../src'), + $excludeList->getExcludedDirectories(), + ); + } + + public function testExclusionOfFileCanBeQueried(): void + { + $excludeList = new ExcludeList(true); + + $this->assertTrue($excludeList->isExcluded(realpath(__DIR__ . '/../../../src/Framework/TestCase.php'))); + $this->assertFalse($excludeList->isExcluded(__FILE__)); + } + + public function testCanBeDisabled(): void + { + $excludeList = new ExcludeList(false); + + $this->assertFalse($excludeList->isExcluded(realpath(__DIR__ . '/../../../src/Framework/TestCase.php'))); + } + + public function testAdditionalDirectoryCanBeExcluded(): void + { + $directory = realpath(__DIR__); + + ExcludeList::addDirectory($directory); + + $excludeList = new ExcludeList(true); + + $this->assertContains($directory, $excludeList->getExcludedDirectories()); + } + + public function testAdditionalDirectoryThatDoesNotExistCannotBeExcluded(): void + { + $this->expectException(InvalidDirectoryException::class); + + ExcludeList::addDirectory('/does/not/exist'); + } +} diff --git a/tests/unit/Util/FilesystemTest.php b/tests/unit/Util/FilesystemTest.php new file mode 100644 index 00000000000..2543bc693c0 --- /dev/null +++ b/tests/unit/Util/FilesystemTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use const DIRECTORY_SEPARATOR; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Filesystem::class)] +#[Small] +final class FilesystemTest extends TestCase +{ + public function testCanResolveStreamOrFile(): void + { + $this->assertSame('php://stdout', Filesystem::resolveStreamOrFile('php://stdout')); + $this->assertSame('socket://hostname:port', Filesystem::resolveStreamOrFile('socket://hostname:port')); + $this->assertSame(__FILE__, Filesystem::resolveStreamOrFile(__FILE__)); + $this->assertSame(__DIR__ . DIRECTORY_SEPARATOR . 'does-not-exist', Filesystem::resolveStreamOrFile(__DIR__ . '/does-not-exist')); + $this->assertFalse(Filesystem::resolveStreamOrFile(__DIR__ . '/does-not-exist/does-not-exist')); + } +} diff --git a/tests/unit/Util/FilterTest.php b/tests/unit/Util/FilterTest.php new file mode 100644 index 00000000000..01056ba7623 --- /dev/null +++ b/tests/unit/Util/FilterTest.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use Exception; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Test::class)] +#[Small] +final class FilterTest extends TestCase +{ + public function testUnwrapThrowableUsesPreviousValues(): void + { + $first = new Exception('first', 123, null); + $second = new Exception('second', 345, $first); + + $this->assertSame(Filter::stackTraceFromThrowableAsString($second), Filter::stackTraceFromThrowableAsString($first)); + } +} diff --git a/tests/unit/Util/GlobalStateTest.php b/tests/unit/Util/GlobalStateTest.php new file mode 100644 index 00000000000..a34151bb593 --- /dev/null +++ b/tests/unit/Util/GlobalStateTest.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(GlobalState::class)] +#[Small] +final class GlobalStateTest extends TestCase +{ + public function testIncludedFilesAsStringSkipsVfsProtocols(): void + { + $dir = __DIR__; + $files = [ + 'phpunit', // The 0 index is not used + $dir . '/GlobalStateTest.php', + 'vfs://' . $dir . '/RegexTest.php', + 'phpvfs53e46260465c7://' . $dir . '/TestClassTest.php', + 'file://' . $dir . '/XmlTest.php', + ]; + + $this->assertEquals( + "require_once '" . $dir . "/GlobalStateTest.php';\n" . + "require_once 'file://" . $dir . "/XmlTest.php';\n", + GlobalState::processIncludedFilesAsString($files), + ); + } +} diff --git a/tests/unit/Util/JsonTest.php b/tests/unit/Util/JsonTest.php new file mode 100644 index 00000000000..ce7fdd687fe --- /dev/null +++ b/tests/unit/Util/JsonTest.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Json::class)] +#[Small] +final class JsonTest extends TestCase +{ + public static function canonicalizeProvider(): array + { + return [ + ['{"name":"John","age":"35"}', '{"age":"35","name":"John"}', false], + ['{"name":"John","age":"35","kids":[{"name":"Petr","age":"5"}]}', '{"age":"35","kids":[{"age":"5","name":"Petr"}],"name":"John"}', false], + ['"name":"John","age":"35"}', '{"age":"35","name":"John"}', true], + ]; + } + + public static function prettifyProvider(): array + { + return [ + ['{"name":"John","age": "5"}', "{\n \"name\": \"John\",\n \"age\": \"5\"\n}"], + ['{"url":"https://www.example.com/"}', "{\n \"url\": \"https://www.example.com//"\n}"], + ['"Кириллица and 中文"', '"Кириллица and 中文"'], + ]; + } + + public static function prettifyExceptionProvider(): array + { + return [ + ['"name":"John","age": "5"}'], + [''], + ]; + } + + #[DataProvider('canonicalizeProvider')] + #[TestDox('Canonicalize $actual')] + public function testCanonicalize(string $actual, string $expected, bool $expectError): void + { + [$error, $canonicalized] = Json::canonicalize($actual); + + $this->assertEquals($expectError, $error); + + if (!$expectError) { + $this->assertEquals($expected, $canonicalized); + } + } + + #[DataProvider('prettifyProvider')] + #[TestDox('Prettify $actual to $expected')] + public function testPrettify(string $actual, string $expected): void + { + $this->assertEquals($expected, Json::prettify($actual)); + } + + #[DataProvider('prettifyExceptionProvider')] + public function testPrettifyException(string $json): void + { + $this->expectException(InvalidJsonException::class); + + Json::prettify($json); + } +} diff --git a/tests/unit/Util/PHP/DefaultJobRunnerTest.php b/tests/unit/Util/PHP/DefaultJobRunnerTest.php new file mode 100644 index 00000000000..6c3bdf48254 --- /dev/null +++ b/tests/unit/Util/PHP/DefaultJobRunnerTest.php @@ -0,0 +1,132 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use Generator; +use PHPUnit\Event\Emitter; +use PHPUnit\Event\Facade; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\UsesClass; +use PHPUnit\Framework\ChildProcessResultProcessor; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\CodeCoverage; +use PHPUnit\TestRunner\TestResult\PassedTests; + +#[CoversClass(DefaultJobRunner::class)] +#[UsesClass(Job::class)] +#[UsesClass(Result::class)] +#[Small] +final class DefaultJobRunnerTest extends TestCase +{ + public static function provider(): Generator + { + yield 'output to stdout' => [ + new Result('test', ''), + new Job( + <<<'EOT' + [ + new Result('', 'test'), + new Job( + <<<'EOT' + [ + new Result('test-stdout', 'test-stderr'), + new Job( + <<<'EOT' + [ + new Result('test', ''), + new Job( + <<<'EOT' + [ + new Result('test', ''), + new Job( + <<<'EOT' + 'test'], + ), + ]; + + yield 'arguments' => [ + new Result('test', ''), + new Job( + <<<'EOT' + [ + new Result('test', ''), + new Job( + <<<'EOT' +createStub(Emitter::class), + new PassedTests, + new CodeCoverage, + ), + ); + + $result = $jobRunner->run($job); + + $this->assertSame($expected->stdout(), $result->stdout()); + $this->assertSame($expected->stderr(), $result->stderr()); + } +} diff --git a/tests/unit/Util/PHP/JobTest.php b/tests/unit/Util/PHP/JobTest.php new file mode 100644 index 00000000000..e2b9a6fd1a4 --- /dev/null +++ b/tests/unit/Util/PHP/JobTest.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Job::class)] +#[Small] +final class JobTest extends TestCase +{ + public function testHasCode(): void + { + $code = 'the-code'; + + $job = new Job( + $code, + [], + [], + [], + null, + false, + ); + + $this->assertSame($code, $job->code()); + + $this->assertFalse($job->hasEnvironmentVariables()); + $this->assertFalse($job->hasInput()); + $this->assertFalse($job->redirectErrors()); + } + + public function testMayHavePhpSettings(): void + { + $phpSettings = ['foo' => 'bar']; + + $job = new Job( + 'the-code', + $phpSettings, + [], + [], + null, + false, + ); + + $this->assertSame($phpSettings, $job->phpSettings()); + + $this->assertFalse($job->hasEnvironmentVariables()); + $this->assertFalse($job->hasInput()); + $this->assertFalse($job->redirectErrors()); + } + + public function testMayHaveEnvironmentVariables(): void + { + $environmentVariables = ['foo' => 'bar']; + + $job = new Job( + 'the-code', + [], + $environmentVariables, + [], + null, + false, + ); + + $this->assertTrue($job->hasEnvironmentVariables()); + $this->assertSame($environmentVariables, $job->environmentVariables()); + + $this->assertFalse($job->hasInput()); + $this->assertFalse($job->redirectErrors()); + } + + public function testMayHaveArguments(): void + { + $arguments = ['foo', 'bar']; + + $job = new Job( + 'the-code', + [], + [], + $arguments, + null, + false, + ); + + $this->assertTrue($job->hasArguments()); + $this->assertSame($arguments, $job->arguments()); + + $this->assertFalse($job->hasEnvironmentVariables()); + $this->assertFalse($job->hasInput()); + $this->assertFalse($job->redirectErrors()); + } + + public function testMayHaveInput(): void + { + $input = 'the-input'; + + $job = new Job( + 'the-code', + [], + [], + [], + $input, + false, + ); + + $this->assertTrue($job->hasInput()); + $this->assertSame($input, $job->input()); + + $this->assertFalse($job->hasEnvironmentVariables()); + $this->assertFalse($job->redirectErrors()); + } + + public function testMayNotHaveInput(): void + { + $job = new Job( + 'the-code', + [], + [], + [], + null, + false, + ); + + $this->assertFalse($job->hasInput()); + + $this->expectException(PhpProcessException::class); + + $job->input(); + } + + public function testMayRedirectErrors(): void + { + $job = new Job( + 'the-code', + [], + [], + [], + null, + true, + ); + + $this->assertTrue($job->redirectErrors()); + } +} diff --git a/tests/unit/Util/PHP/ResultTest.php b/tests/unit/Util/PHP/ResultTest.php new file mode 100644 index 00000000000..c8597f2fbd7 --- /dev/null +++ b/tests/unit/Util/PHP/ResultTest.php @@ -0,0 +1,34 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\PHP; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Result::class)] +#[Small] +final class ResultTest extends TestCase +{ + public function testHasOutputFromStdout(): void + { + $this->assertSame('stdout', $this->fixture()->stdout()); + } + + public function testHasOutputFromStderr(): void + { + $this->assertSame('stderr', $this->fixture()->stderr()); + } + + private function fixture(): Result + { + return new Result('stdout', 'stderr'); + } +} diff --git a/tests/unit/Util/ReflectionTest.php b/tests/unit/Util/ReflectionTest.php new file mode 100644 index 00000000000..30cb057c009 --- /dev/null +++ b/tests/unit/Util/ReflectionTest.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function realpath; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\BankAccountTest; +use PHPUnit\TestFixture\ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest; +use ReflectionClass; + +#[CoversClass(Reflection::class)] +#[Small] +final class ReflectionTest extends TestCase +{ + public function testFindsSourceLocationForMethod(): void + { + $this->assertSame( + [ + 'file' => realpath(__DIR__ . '/../../_files/BankAccountTest.php'), + 'line' => 22, + ], + Reflection::sourceLocationFor(BankAccountTest::class, 'testBalanceIsInitiallyZero'), + ); + } + + public function testFindsSourceLocationForMethodInAbstractTestCase(): void + { + $this->assertSame( + [ + 'file' => realpath(__DIR__ . '/../../_files/abstract/without-test-suffix/AbstractTestCase.php'), + 'line' => 16, + ], + Reflection::sourceLocationFor(ConcreteTestClassExtendingAbstractTestClassWithoutTestSuffixTest::class, 'testOne'), + ); + } + + public function testReturnsUnknownSourceLocationForMethodThatDoesNotExist(): void + { + $this->assertSame( + [ + 'file' => 'unknown', + 'line' => 0, + ], + Reflection::sourceLocationFor('DoesNotExist', 'doesNotExist'), + ); + } + + public function testFindsPublicMethodsInTestClass(): void + { + $methods = Reflection::publicMethodsDeclaredDirectlyInTestClass(new ReflectionClass(BankAccountTest::class)); + + $this->assertCount(3, $methods); + $this->assertSame('testBalanceIsInitiallyZero', $methods[0]->getName()); + $this->assertSame('testBalanceCannotBecomeNegative', $methods[1]->getName()); + $this->assertSame('testBalanceCannotBecomeNegative2', $methods[2]->getName()); + } + + public function testFindsMethodsInTestClass(): void + { + $methods = Reflection::methodsDeclaredDirectlyInTestClass(new ReflectionClass(BankAccountTest::class)); + + $this->assertCount(3, $methods); + $this->assertSame('testBalanceIsInitiallyZero', $methods[0]->getName()); + $this->assertSame('testBalanceCannotBecomeNegative', $methods[1]->getName()); + $this->assertSame('testBalanceCannotBecomeNegative2', $methods[2]->getName()); + } +} diff --git a/tests/unit/Util/TestTest.php b/tests/unit/Util/TestTest.php new file mode 100644 index 00000000000..ad78c9f238e --- /dev/null +++ b/tests/unit/Util/TestTest.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TestFixture\TestCaseTest; +use ReflectionMethod; + +#[CoversClass(Test::class)] +#[Small] +final class TestTest extends TestCase +{ + public static function provider(): array + { + return [ + [true, new ReflectionMethod(TestCaseTest::class, 'testOne')], + [true, new ReflectionMethod(TestCaseTest::class, 'two')], + [false, new ReflectionMethod(TestCaseTest::class, 'three')], + [false, new ReflectionMethod(TestCaseTest::class, 'four')], + ]; + } + + #[DataProvider('provider')] + public function testDetectsTestMethods(bool $result, ReflectionMethod $method): void + { + $this->assertSame($result, Test::isTestMethod($method)); + } +} diff --git a/tests/unit/Util/ThrowableToStringMapperTest.php b/tests/unit/Util/ThrowableToStringMapperTest.php new file mode 100644 index 00000000000..edf09ca6383 --- /dev/null +++ b/tests/unit/Util/ThrowableToStringMapperTest.php @@ -0,0 +1,67 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\ExpectationFailedException; +use PHPUnit\Framework\PhptAssertionFailedError; +use PHPUnit\Framework\TestCase; +use PHPUnit\Runner\ErrorException; +use RuntimeException; +use SebastianBergmann\Comparator\ComparisonFailure; + +#[CoversClass(ThrowableToStringMapper::class)] +#[Small] +#[TestDox('ThrowableToStringMapper')] +final class ThrowableToStringMapperTest extends TestCase +{ + #[TestDox('Maps ExpectationFailedException with ComparisonFailure')] + public function testMapsExpectationFailedExceptionWithComparisonFailure(): void + { + $comparisonFailure = new ComparisonFailure('expected', 'actual', 'expected', 'actual'); + $e = new ExpectationFailedException('msg', $comparisonFailure); + + $mapped = ThrowableToStringMapper::map($e); + + $this->assertStringContainsString('msg', $mapped); + $this->assertStringContainsString($comparisonFailure->getDiff(), $mapped); + $this->assertStringEndsWith("\n", $mapped); + } + + #[TestDox('Maps PhptAssertionFailedError')] + public function testMapsPhptAssertionFailedError(): void + { + $error = new PhptAssertionFailedError('phpt-message', 0, 'file', 1, [], 'my-diff-string'); + $mapped = ThrowableToStringMapper::map($error); + + $this->assertStringContainsString('phpt-message', $mapped); + $this->assertStringContainsString('my-diff-string', $mapped); + $this->assertStringEndsWith("\n", $mapped); + } + + #[TestDox('Maps \ErrorException')] + public function testMapsErrorException(): void + { + $e = new ErrorException('boom'); + + $this->assertSame('boom', ThrowableToStringMapper::map($e)); + } + + #[TestDox('Maps \Throwable')] + public function testMapsThrowable(): void + { + $t = new RuntimeException('oops'); + $expected = RuntimeException::class . ': oops' . "\n"; + + $this->assertSame($expected, ThrowableToStringMapper::map($t)); + } +} diff --git a/tests/unit/Util/VersionComparisonOperatorTest.php b/tests/unit/Util/VersionComparisonOperatorTest.php new file mode 100644 index 00000000000..39745275a9d --- /dev/null +++ b/tests/unit/Util/VersionComparisonOperatorTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\Attributes\TestDox; +use PHPUnit\Framework\TestCase; + +#[CoversClass(VersionComparisonOperator::class)] +#[CoversClass(InvalidVersionOperatorException::class)] +#[Small] +final class VersionComparisonOperatorTest extends TestCase +{ + /** + * @return non-empty-list> + */ + public static function validValues(): array + { + return [ + ['<'], + ['lt'], + ['<='], + ['le'], + ['>'], + ['gt'], + ['>='], + ['ge'], + ['=='], + ['='], + ['eq'], + ['!='], + ['<>'], + ['ne'], + ]; + } + + #[DataProvider('validValues')] + #[TestDox('Can be created from "$string"')] + public function testCanBeCreatedFromValidString(string $string): void + { + $this->assertSame($string, new VersionComparisonOperator($string)->asString()); + } + + public function testCannotBeCreatedFromInvalidString(): void + { + $this->expectException(InvalidVersionOperatorException::class); + + new VersionComparisonOperator(''); + } +} diff --git a/tests/unit/Util/Xml/LoaderTest.php b/tests/unit/Util/Xml/LoaderTest.php new file mode 100644 index 00000000000..44a31321299 --- /dev/null +++ b/tests/unit/Util/Xml/LoaderTest.php @@ -0,0 +1,73 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util\Xml; + +use DOMDocument; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; + +#[CoversClass(Loader::class)] +#[Small] +final class LoaderTest extends TestCase +{ + public function testCanParseFileWithValidXml(): void + { + $document = (new Loader)->loadFile(__DIR__ . '/../../../_files/configuration.xml'); + + $this->assertInstanceOf(DOMDocument::class, $document); + } + + public function testCannotParseFileThatDoesNotExist(): void + { + $this->expectException(XmlException::class); + $this->expectExceptionMessage('Could not read XML from file "/does/not/exist.xml"'); + + (new Loader)->loadFile('/does/not/exist.xml'); + } + + public function testCannotParseEmptyFile(): void + { + $this->expectException(XmlException::class); + + (new Loader)->loadFile(__DIR__ . '/../../../_files/empty.xml'); + } + + public function testCannotParseFileWithInvalidXml(): void + { + $this->expectException(XmlException::class); + $this->expectExceptionMessageMatches("#Premature end of data in tag test line 1|EndTag: 'loadFile(__DIR__ . '/../../../_files/invalid.xml'); + } + + public function testCanParseStringWithValidXml(): void + { + $document = (new Loader)->load(''); + + $this->assertInstanceOf(DOMDocument::class, $document); + } + + public function testCannotParseEmptyString(): void + { + $this->expectException(XmlException::class); + $this->expectExceptionMessage('Could not parse XML from empty string'); + + (new Loader)->load(''); + } + + public function testCannotParseStringWithInvalidXml(): void + { + $this->expectException(XmlException::class); + $this->expectExceptionMessageMatches("#Premature end of data in tag test line 1|EndTag: 'load(''); + } +} diff --git a/tests/unit/Util/XmlTest.php b/tests/unit/Util/XmlTest.php new file mode 100644 index 00000000000..120183ed864 --- /dev/null +++ b/tests/unit/Util/XmlTest.php @@ -0,0 +1,62 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ +namespace PHPUnit\Util; + +use function chr; +use function ord; +use function sprintf; +use DOMDocument; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\DataProvider; +use PHPUnit\Framework\Attributes\Small; +use PHPUnit\Framework\TestCase; +use PHPUnit\TextUI\XmlConfiguration\ValidationResult; + +#[CoversClass(Xml::class)] +#[CoversClass(ValidationResult::class)] +#[Small] +final class XmlTest extends TestCase +{ + public static function charProvider(): array + { + $data = []; + + for ($i = 0; $i < 256; $i++) { + $data[] = [chr($i)]; + } + + return $data; + } + + #[DataProvider('charProvider')] + public function testPrepareString(string $char): void + { + $e = null; + + $escapedString = Xml::prepareString($char); + $xml = "{$escapedString}"; + $dom = new DOMDocument('1.0', 'UTF-8'); + + try { + $dom->loadXML($xml); + } catch (Exception $e) { + } + + $this->assertNull( + $e, + sprintf( + '%s::prepareString("\x%02x") should not crash %s', + Xml::class, + ord($char), + DOMDocument::class, + ), + ); + } +} diff --git a/tools/.phpstan/composer.json b/tools/.phpstan/composer.json new file mode 100644 index 00000000000..8e13d135957 --- /dev/null +++ b/tools/.phpstan/composer.json @@ -0,0 +1,14 @@ +{ + "require-dev": { + "phpstan/phpstan": "^2.1.33", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-strict-rules": "^2.0.7", + "tomasvotruba/type-coverage": "^2.1.0", + "ergebnis/phpstan-rules": "^2.12.0" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true + } + } +} diff --git a/tools/.phpstan/composer.lock b/tools/.phpstan/composer.lock new file mode 100644 index 00000000000..c99f4b27de7 --- /dev/null +++ b/tools/.phpstan/composer.lock @@ -0,0 +1,387 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "4409cdc49212f7e878b14b7ae9285bb2", + "packages": [], + "packages-dev": [ + { + "name": "ergebnis/phpstan-rules", + "version": "2.12.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/phpstan-rules.git", + "reference": "c4e0121a937b3b551f800a86e7d78794da2783ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/c4e0121a937b3b551f800a86e7d78794da2783ea", + "reference": "c4e0121a937b3b551f800a86e7d78794da2783ea", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpstan/phpstan": "^2.1.8" + }, + "require-dev": { + "codeception/codeception": "^4.0.0 || ^5.0.0", + "doctrine/orm": "^2.20.0 || ^3.3.0", + "ergebnis/composer-normalize": "^2.47.0", + "ergebnis/license": "^2.6.0", + "ergebnis/php-cs-fixer-config": "^6.54.0", + "ergebnis/phpunit-slow-test-detector": "^2.20.0", + "fakerphp/faker": "^1.24.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "phpunit/phpunit": "^9.6.21", + "psr/container": "^2.0.2", + "symfony/finder": "^5.4.45", + "symfony/process": "^5.4.47" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "Ergebnis\\PHPStan\\Rules\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com/" + } + ], + "description": "Provides rules for phpstan/phpstan.", + "homepage": "https://github.com/ergebnis/phpstan-rules", + "keywords": [ + "PHPStan", + "phpstan-rules" + ], + "support": { + "issues": "https://github.com/ergebnis/phpstan-rules/issues", + "security": "https://github.com/ergebnis/phpstan-rules/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/phpstan-rules" + }, + "time": "2025-09-07T13:31:33+00:00" + }, + { + "name": "nette/utils", + "version": "v4.1.0", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/tester": "^2.5", + "phpstan/phpstan-nette": "^2.0@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com/" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org/", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.0" + }, + "time": "2025-12-01T17:49:23+00:00" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "time": "2024-09-04T20:21:43+00:00" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.33", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "time": "2025-12-05T10:24:31+00:00" + }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "2.0.7", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/d6211c46213d4181054b3d77b10a5c5cb0d59538", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.29" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.7" + }, + "time": "2025-09-26T11:19:08+00:00" + }, + { + "name": "tomasvotruba/type-coverage", + "version": "2.1.0", + "source": { + "type": "git", + "url": "https://github.com/TomasVotruba/type-coverage.git", + "reference": "468354b3964120806a69890cbeb3fcf005876391" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TomasVotruba/type-coverage/zipball/468354b3964120806a69890cbeb3fcf005876391", + "reference": "468354b3964120806a69890cbeb3fcf005876391", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2 || ^4.0", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "config/extension.neon" + ] + } + }, + "autoload": { + "psr-4": { + "TomasVotruba\\TypeCoverage\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Measure type coverage of your project", + "keywords": [ + "phpstan-extension", + "static analysis" + ], + "support": { + "issues": "https://github.com/TomasVotruba/type-coverage/issues", + "source": "https://github.com/TomasVotruba/type-coverage/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "time": "2025-12-05T16:38:02+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": false, + "prefer-lowest": false, + "platform": {}, + "platform-dev": {}, + "plugin-api-version": "2.9.0" +} diff --git a/tools/.phpstan/vendor/autoload.php b/tools/.phpstan/vendor/autoload.php new file mode 100644 index 00000000000..94a663ef036 --- /dev/null +++ b/tools/.phpstan/vendor/autoload.php @@ -0,0 +1,22 @@ +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan'); + } +} + +return include __DIR__ . '/..'.'/phpstan/phpstan/phpstan'; diff --git a/tools/.phpstan/vendor/bin/phpstan.phar b/tools/.phpstan/vendor/bin/phpstan.phar new file mode 100755 index 00000000000..fecf96f69d9 --- /dev/null +++ b/tools/.phpstan/vendor/bin/phpstan.phar @@ -0,0 +1,119 @@ +#!/usr/bin/env php +realpath = realpath($opened_path) ?: $opened_path; + $opened_path = $this->realpath; + $this->handle = fopen($this->realpath, $mode); + $this->position = 0; + + return (bool) $this->handle; + } + + public function stream_read($count) + { + $data = fread($this->handle, $count); + + if ($this->position === 0) { + $data = preg_replace('{^#!.*\r?\n}', '', $data); + } + + $this->position += strlen($data); + + return $data; + } + + public function stream_cast($castAs) + { + return $this->handle; + } + + public function stream_close() + { + fclose($this->handle); + } + + public function stream_lock($operation) + { + return $operation ? flock($this->handle, $operation) : true; + } + + public function stream_seek($offset, $whence) + { + if (0 === fseek($this->handle, $offset, $whence)) { + $this->position = ftell($this->handle); + return true; + } + + return false; + } + + public function stream_tell() + { + return $this->position; + } + + public function stream_eof() + { + return feof($this->handle); + } + + public function stream_stat() + { + return array(); + } + + public function stream_set_option($option, $arg1, $arg2) + { + return true; + } + + public function url_stat($path, $flags) + { + $path = substr($path, 17); + if (file_exists($path)) { + return stat($path); + } + + return false; + } + } + } + + if ( + (function_exists('stream_get_wrappers') && in_array('phpvfscomposer', stream_get_wrappers(), true)) + || (function_exists('stream_wrapper_register') && stream_wrapper_register('phpvfscomposer', 'Composer\BinProxyWrapper')) + ) { + return include("phpvfscomposer://" . __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar'); + } +} + +return include __DIR__ . '/..'.'/phpstan/phpstan/phpstan.phar'; diff --git a/tools/.phpstan/vendor/composer/ClassLoader.php b/tools/.phpstan/vendor/composer/ClassLoader.php new file mode 100644 index 00000000000..7824d8f7eaf --- /dev/null +++ b/tools/.phpstan/vendor/composer/ClassLoader.php @@ -0,0 +1,579 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see https://www.php-fig.org/psr/psr-0/ + * @see https://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ + private $vendorDir; + + // PSR-4 + /** + * @var array> + */ + private $prefixLengthsPsr4 = array(); + /** + * @var array> + */ + private $prefixDirsPsr4 = array(); + /** + * @var list + */ + private $fallbackDirsPsr4 = array(); + + // PSR-0 + /** + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array>> + */ + private $prefixesPsr0 = array(); + /** + * @var list + */ + private $fallbackDirsPsr0 = array(); + + /** @var bool */ + private $useIncludePath = false; + + /** + * @var array + */ + private $classMap = array(); + + /** @var bool */ + private $classMapAuthoritative = false; + + /** + * @var array + */ + private $missingClasses = array(); + + /** @var string|null */ + private $apcuPrefix; + + /** + * @var array + */ + private static $registeredLoaders = array(); + + /** + * @param string|null $vendorDir + */ + public function __construct($vendorDir = null) + { + $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); + } + + /** + * @return array> + */ + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', array_values($this->prefixesPsr0)); + } + + return array(); + } + + /** + * @return array> + */ + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + /** + * @return list + */ + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + /** + * @return list + */ + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + /** + * @return array Array of classname => path + */ + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + * + * @return void + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + * + * @return void + */ + public function add($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + $paths = (array) $paths; + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param list|string $paths The PSR-0 base directories + * + * @return void + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + * + * @return void + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + * + * @return void + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + * + * @return void + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + * + * @return void + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + * + * @return void + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + + if (null === $this->vendorDir) { + return; + } + + if ($prepend) { + self::$registeredLoaders = array($this->vendorDir => $this) + self::$registeredLoaders; + } else { + unset(self::$registeredLoaders[$this->vendorDir]); + self::$registeredLoaders[$this->vendorDir] = $this; + } + } + + /** + * Unregisters this instance as an autoloader. + * + * @return void + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + + if (null !== $this->vendorDir) { + unset(self::$registeredLoaders[$this->vendorDir]); + } + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return true|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + $includeFile = self::$includeFile; + $includeFile($file); + + return true; + } + + return null; + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + /** + * Returns the currently registered loaders keyed by their corresponding vendor directories. + * + * @return array + */ + public static function getRegisteredLoaders() + { + return self::$registeredLoaders; + } + + /** + * @param string $class + * @param string $ext + * @return string|false + */ + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath . '\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } + + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } +} diff --git a/tools/.phpstan/vendor/composer/InstalledVersions.php b/tools/.phpstan/vendor/composer/InstalledVersions.php new file mode 100644 index 00000000000..2052022fd8e --- /dev/null +++ b/tools/.phpstan/vendor/composer/InstalledVersions.php @@ -0,0 +1,396 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer; + +use Composer\Autoload\ClassLoader; +use Composer\Semver\VersionParser; + +/** + * This class is copied in every Composer installed project and available to all + * + * See also https://getcomposer.org/doc/07-runtime.md#installed-versions + * + * To require its presence, you can require `composer-runtime-api ^2.0` + * + * @final + */ +class InstalledVersions +{ + /** + * @var string|null if set (by reflection by Composer), this should be set to the path where this class is being copied to + * @internal + */ + private static $selfDir = null; + + /** + * @var mixed[]|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array}|array{}|null + */ + private static $installed; + + /** + * @var bool + */ + private static $installedIsLocalDir; + + /** + * @var bool|null + */ + private static $canGetVendors; + + /** + * @var array[] + * @psalm-var array}> + */ + private static $installedByVendor = array(); + + /** + * Returns a list of all package names which are present, either by being installed, replaced or provided + * + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackages() + { + $packages = array(); + foreach (self::getInstalled() as $installed) { + $packages[] = array_keys($installed['versions']); + } + + if (1 === \count($packages)) { + return $packages[0]; + } + + return array_keys(array_flip(\call_user_func_array('array_merge', $packages))); + } + + /** + * Returns a list of all package names with a specific type e.g. 'library' + * + * @param string $type + * @return string[] + * @psalm-return list + */ + public static function getInstalledPackagesByType($type) + { + $packagesByType = array(); + + foreach (self::getInstalled() as $installed) { + foreach ($installed['versions'] as $name => $package) { + if (isset($package['type']) && $package['type'] === $type) { + $packagesByType[] = $name; + } + } + } + + return $packagesByType; + } + + /** + * Checks whether the given package is installed + * + * This also returns true if the package name is provided or replaced by another package + * + * @param string $packageName + * @param bool $includeDevRequirements + * @return bool + */ + public static function isInstalled($packageName, $includeDevRequirements = true) + { + foreach (self::getInstalled() as $installed) { + if (isset($installed['versions'][$packageName])) { + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; + } + } + + return false; + } + + /** + * Checks whether the given package satisfies a version constraint + * + * e.g. If you want to know whether version 2.3+ of package foo/bar is installed, you would call: + * + * Composer\InstalledVersions::satisfies(new VersionParser, 'foo/bar', '^2.3') + * + * @param VersionParser $parser Install composer/semver to have access to this class and functionality + * @param string $packageName + * @param string|null $constraint A version constraint to check for, if you pass one you have to make sure composer/semver is required by your package + * @return bool + */ + public static function satisfies(VersionParser $parser, $packageName, $constraint) + { + $constraint = $parser->parseConstraints((string) $constraint); + $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); + + return $provided->matches($constraint); + } + + /** + * Returns a version constraint representing all the range(s) which are installed for a given package + * + * It is easier to use this via isInstalled() with the $constraint argument if you need to check + * whether a given version of a package is installed, and not just whether it exists + * + * @param string $packageName + * @return string Version constraint usable with composer/semver + */ + public static function getVersionRanges($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + $ranges = array(); + if (isset($installed['versions'][$packageName]['pretty_version'])) { + $ranges[] = $installed['versions'][$packageName]['pretty_version']; + } + if (array_key_exists('aliases', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['aliases']); + } + if (array_key_exists('replaced', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['replaced']); + } + if (array_key_exists('provided', $installed['versions'][$packageName])) { + $ranges = array_merge($ranges, $installed['versions'][$packageName]['provided']); + } + + return implode(' || ', $ranges); + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['version'])) { + return null; + } + + return $installed['versions'][$packageName]['version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as version, use satisfies or getVersionRanges if you need to know if a given version is present + */ + public static function getPrettyVersion($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['pretty_version'])) { + return null; + } + + return $installed['versions'][$packageName]['pretty_version']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as reference + */ + public static function getReference($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + if (!isset($installed['versions'][$packageName]['reference'])) { + return null; + } + + return $installed['versions'][$packageName]['reference']; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @param string $packageName + * @return string|null If the package is being replaced or provided but is not really installed, null will be returned as install path. Packages of type metapackages also have a null install path. + */ + public static function getInstallPath($packageName) + { + foreach (self::getInstalled() as $installed) { + if (!isset($installed['versions'][$packageName])) { + continue; + } + + return isset($installed['versions'][$packageName]['install_path']) ? $installed['versions'][$packageName]['install_path'] : null; + } + + throw new \OutOfBoundsException('Package "' . $packageName . '" is not installed'); + } + + /** + * @return array + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} + */ + public static function getRootPackage() + { + $installed = self::getInstalled(); + + return $installed[0]['root']; + } + + /** + * Returns the raw installed.php data for custom implementations + * + * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. + * @return array[] + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} + */ + public static function getRawData() + { + @trigger_error('getRawData only returns the first dataset loaded, which may not be what you expect. Use getAllRawData() instead which returns all datasets for all autoloaders present in the process.', E_USER_DEPRECATED); + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + self::$installed = include __DIR__ . '/installed.php'; + } else { + self::$installed = array(); + } + } + + return self::$installed; + } + + /** + * Returns the raw data of all installed.php which are currently loaded for custom implementations + * + * @return array[] + * @psalm-return list}> + */ + public static function getAllRawData() + { + return self::getInstalled(); + } + + /** + * Lets you reload the static array from another file + * + * This is only useful for complex integrations in which a project needs to use + * this class but then also needs to execute another project's autoloader in process, + * and wants to ensure both projects have access to their version of installed.php. + * + * A typical case would be PHPUnit, where it would need to make sure it reads all + * the data it needs from this class, then call reload() with + * `require $CWD/vendor/composer/installed.php` (or similar) as input to make sure + * the project in which it runs can then also use this class safely, without + * interference between PHPUnit's dependencies and the project's dependencies. + * + * @param array[] $data A vendor/composer/installed.php data set + * @return void + * + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $data + */ + public static function reload($data) + { + self::$installed = $data; + self::$installedByVendor = array(); + + // when using reload, we disable the duplicate protection to ensure that self::$installed data is + // always returned, but we cannot know whether it comes from the installed.php in __DIR__ or not, + // so we have to assume it does not, and that may result in duplicate data being returned when listing + // all installed packages for example + self::$installedIsLocalDir = false; + } + + /** + * @return string + */ + private static function getSelfDir() + { + if (self::$selfDir === null) { + self::$selfDir = strtr(__DIR__, '\\', '/'); + } + + return self::$selfDir; + } + + /** + * @return array[] + * @psalm-return list}> + */ + private static function getInstalled() + { + if (null === self::$canGetVendors) { + self::$canGetVendors = method_exists('Composer\Autoload\ClassLoader', 'getRegisteredLoaders'); + } + + $installed = array(); + $copiedLocalDir = false; + + if (self::$canGetVendors) { + $selfDir = self::getSelfDir(); + foreach (ClassLoader::getRegisteredLoaders() as $vendorDir => $loader) { + $vendorDir = strtr($vendorDir, '\\', '/'); + if (isset(self::$installedByVendor[$vendorDir])) { + $installed[] = self::$installedByVendor[$vendorDir]; + } elseif (is_file($vendorDir.'/composer/installed.php')) { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require $vendorDir.'/composer/installed.php'; + self::$installedByVendor[$vendorDir] = $required; + $installed[] = $required; + if (self::$installed === null && $vendorDir.'/composer' === $selfDir) { + self::$installed = $required; + self::$installedIsLocalDir = true; + } + } + if (self::$installedIsLocalDir && $vendorDir.'/composer' === $selfDir) { + $copiedLocalDir = true; + } + } + } + + if (null === self::$installed) { + // only require the installed.php file if this file is loaded from its dumped location, + // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 + if (substr(__DIR__, -8, 1) !== 'C') { + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; + } else { + self::$installed = array(); + } + } + + if (self::$installed !== array() && !$copiedLocalDir) { + $installed[] = self::$installed; + } + + return $installed; + } +} diff --git a/tools/.phpstan/vendor/composer/LICENSE b/tools/.phpstan/vendor/composer/LICENSE new file mode 100644 index 00000000000..f27399a042d --- /dev/null +++ b/tools/.phpstan/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/tools/.phpstan/vendor/composer/autoload_classmap.php b/tools/.phpstan/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000000..c66a950246a --- /dev/null +++ b/tools/.phpstan/vendor/composer/autoload_classmap.php @@ -0,0 +1,60 @@ + $vendorDir . '/composer/InstalledVersions.php', + 'Nette\\ArgumentOutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\DeprecatedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\DirectoryNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\FileNotFoundException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\HtmlStringable' => $vendorDir . '/nette/utils/src/HtmlStringable.php', + 'Nette\\IOException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidArgumentException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidStateException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\Iterators\\CachingIterator' => $vendorDir . '/nette/utils/src/Iterators/CachingIterator.php', + 'Nette\\Iterators\\Mapper' => $vendorDir . '/nette/utils/src/Iterators/Mapper.php', + 'Nette\\Localization\\ITranslator' => $vendorDir . '/nette/utils/src/compatibility.php', + 'Nette\\Localization\\Translator' => $vendorDir . '/nette/utils/src/Translator.php', + 'Nette\\MemberAccessException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\NotImplementedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\NotSupportedException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\OutOfRangeException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\ShouldNotHappenException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\SmartObject' => $vendorDir . '/nette/utils/src/SmartObject.php', + 'Nette\\StaticClass' => $vendorDir . '/nette/utils/src/StaticClass.php', + 'Nette\\UnexpectedValueException' => $vendorDir . '/nette/utils/src/exceptions.php', + 'Nette\\Utils\\ArrayHash' => $vendorDir . '/nette/utils/src/Utils/ArrayHash.php', + 'Nette\\Utils\\ArrayList' => $vendorDir . '/nette/utils/src/Utils/ArrayList.php', + 'Nette\\Utils\\Arrays' => $vendorDir . '/nette/utils/src/Utils/Arrays.php', + 'Nette\\Utils\\AssertionException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Callback' => $vendorDir . '/nette/utils/src/Utils/Callback.php', + 'Nette\\Utils\\DateTime' => $vendorDir . '/nette/utils/src/Utils/DateTime.php', + 'Nette\\Utils\\FileInfo' => $vendorDir . '/nette/utils/src/Utils/FileInfo.php', + 'Nette\\Utils\\FileSystem' => $vendorDir . '/nette/utils/src/Utils/FileSystem.php', + 'Nette\\Utils\\Finder' => $vendorDir . '/nette/utils/src/Utils/Finder.php', + 'Nette\\Utils\\Floats' => $vendorDir . '/nette/utils/src/Utils/Floats.php', + 'Nette\\Utils\\Helpers' => $vendorDir . '/nette/utils/src/Utils/Helpers.php', + 'Nette\\Utils\\Html' => $vendorDir . '/nette/utils/src/Utils/Html.php', + 'Nette\\Utils\\IHtmlString' => $vendorDir . '/nette/utils/src/compatibility.php', + 'Nette\\Utils\\Image' => $vendorDir . '/nette/utils/src/Utils/Image.php', + 'Nette\\Utils\\ImageColor' => $vendorDir . '/nette/utils/src/Utils/ImageColor.php', + 'Nette\\Utils\\ImageException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ImageType' => $vendorDir . '/nette/utils/src/Utils/ImageType.php', + 'Nette\\Utils\\Iterables' => $vendorDir . '/nette/utils/src/Utils/Iterables.php', + 'Nette\\Utils\\Json' => $vendorDir . '/nette/utils/src/Utils/Json.php', + 'Nette\\Utils\\JsonException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ObjectHelpers' => $vendorDir . '/nette/utils/src/Utils/ObjectHelpers.php', + 'Nette\\Utils\\Paginator' => $vendorDir . '/nette/utils/src/Utils/Paginator.php', + 'Nette\\Utils\\Random' => $vendorDir . '/nette/utils/src/Utils/Random.php', + 'Nette\\Utils\\Reflection' => $vendorDir . '/nette/utils/src/Utils/Reflection.php', + 'Nette\\Utils\\ReflectionMethod' => $vendorDir . '/nette/utils/src/Utils/ReflectionMethod.php', + 'Nette\\Utils\\RegexpException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Strings' => $vendorDir . '/nette/utils/src/Utils/Strings.php', + 'Nette\\Utils\\Type' => $vendorDir . '/nette/utils/src/Utils/Type.php', + 'Nette\\Utils\\UnknownImageFileException' => $vendorDir . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Validators' => $vendorDir . '/nette/utils/src/Utils/Validators.php', +); diff --git a/tools/.phpstan/vendor/composer/autoload_files.php b/tools/.phpstan/vendor/composer/autoload_files.php new file mode 100644 index 00000000000..b62e293ba24 --- /dev/null +++ b/tools/.phpstan/vendor/composer/autoload_files.php @@ -0,0 +1,10 @@ + $vendorDir . '/phpstan/phpstan/bootstrap.php', +); diff --git a/tools/.phpstan/vendor/composer/autoload_namespaces.php b/tools/.phpstan/vendor/composer/autoload_namespaces.php new file mode 100644 index 00000000000..15a2ff3ad6d --- /dev/null +++ b/tools/.phpstan/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ + array($vendorDir . '/tomasvotruba/type-coverage/src'), + 'PHPStan\\ExtensionInstaller\\' => array($vendorDir . '/phpstan/extension-installer/src'), + 'PHPStan\\' => array($vendorDir . '/phpstan/phpstan-strict-rules/src'), + 'Nette\\' => array($vendorDir . '/nette/utils/src'), + 'Ergebnis\\PHPStan\\Rules\\' => array($vendorDir . '/ergebnis/phpstan-rules/src'), +); diff --git a/tools/.phpstan/vendor/composer/autoload_real.php b/tools/.phpstan/vendor/composer/autoload_real.php new file mode 100644 index 00000000000..c91f94e3d39 --- /dev/null +++ b/tools/.phpstan/vendor/composer/autoload_real.php @@ -0,0 +1,48 @@ +register(true); + + $filesToLoad = \Composer\Autoload\ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7::$files; + $requireFile = \Closure::bind(static function ($fileIdentifier, $file) { + if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) { + $GLOBALS['__composer_autoload_files'][$fileIdentifier] = true; + + require $file; + } + }, null, null); + foreach ($filesToLoad as $fileIdentifier => $file) { + $requireFile($fileIdentifier, $file); + } + + return $loader; + } +} diff --git a/tools/.phpstan/vendor/composer/autoload_static.php b/tools/.phpstan/vendor/composer/autoload_static.php new file mode 100644 index 00000000000..b66b4992eae --- /dev/null +++ b/tools/.phpstan/vendor/composer/autoload_static.php @@ -0,0 +1,119 @@ + __DIR__ . '/..' . '/phpstan/phpstan/bootstrap.php', + ); + + public static $prefixLengthsPsr4 = array ( + 'T' => + array ( + 'TomasVotruba\\TypeCoverage\\' => 26, + ), + 'P' => + array ( + 'PHPStan\\ExtensionInstaller\\' => 27, + 'PHPStan\\' => 8, + ), + 'N' => + array ( + 'Nette\\' => 6, + ), + 'E' => + array ( + 'Ergebnis\\PHPStan\\Rules\\' => 23, + ), + ); + + public static $prefixDirsPsr4 = array ( + 'TomasVotruba\\TypeCoverage\\' => + array ( + 0 => __DIR__ . '/..' . '/tomasvotruba/type-coverage/src', + ), + 'PHPStan\\ExtensionInstaller\\' => + array ( + 0 => __DIR__ . '/..' . '/phpstan/extension-installer/src', + ), + 'PHPStan\\' => + array ( + 0 => __DIR__ . '/..' . '/phpstan/phpstan-strict-rules/src', + ), + 'Nette\\' => + array ( + 0 => __DIR__ . '/..' . '/nette/utils/src', + ), + 'Ergebnis\\PHPStan\\Rules\\' => + array ( + 0 => __DIR__ . '/..' . '/ergebnis/phpstan-rules/src', + ), + ); + + public static $classMap = array ( + 'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php', + 'Nette\\ArgumentOutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\DeprecatedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\DirectoryNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\FileNotFoundException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\HtmlStringable' => __DIR__ . '/..' . '/nette/utils/src/HtmlStringable.php', + 'Nette\\IOException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidArgumentException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\InvalidStateException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\Iterators\\CachingIterator' => __DIR__ . '/..' . '/nette/utils/src/Iterators/CachingIterator.php', + 'Nette\\Iterators\\Mapper' => __DIR__ . '/..' . '/nette/utils/src/Iterators/Mapper.php', + 'Nette\\Localization\\ITranslator' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'Nette\\Localization\\Translator' => __DIR__ . '/..' . '/nette/utils/src/Translator.php', + 'Nette\\MemberAccessException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\NotImplementedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\NotSupportedException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\OutOfRangeException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\ShouldNotHappenException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\SmartObject' => __DIR__ . '/..' . '/nette/utils/src/SmartObject.php', + 'Nette\\StaticClass' => __DIR__ . '/..' . '/nette/utils/src/StaticClass.php', + 'Nette\\UnexpectedValueException' => __DIR__ . '/..' . '/nette/utils/src/exceptions.php', + 'Nette\\Utils\\ArrayHash' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayHash.php', + 'Nette\\Utils\\ArrayList' => __DIR__ . '/..' . '/nette/utils/src/Utils/ArrayList.php', + 'Nette\\Utils\\Arrays' => __DIR__ . '/..' . '/nette/utils/src/Utils/Arrays.php', + 'Nette\\Utils\\AssertionException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Callback' => __DIR__ . '/..' . '/nette/utils/src/Utils/Callback.php', + 'Nette\\Utils\\DateTime' => __DIR__ . '/..' . '/nette/utils/src/Utils/DateTime.php', + 'Nette\\Utils\\FileInfo' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileInfo.php', + 'Nette\\Utils\\FileSystem' => __DIR__ . '/..' . '/nette/utils/src/Utils/FileSystem.php', + 'Nette\\Utils\\Finder' => __DIR__ . '/..' . '/nette/utils/src/Utils/Finder.php', + 'Nette\\Utils\\Floats' => __DIR__ . '/..' . '/nette/utils/src/Utils/Floats.php', + 'Nette\\Utils\\Helpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/Helpers.php', + 'Nette\\Utils\\Html' => __DIR__ . '/..' . '/nette/utils/src/Utils/Html.php', + 'Nette\\Utils\\IHtmlString' => __DIR__ . '/..' . '/nette/utils/src/compatibility.php', + 'Nette\\Utils\\Image' => __DIR__ . '/..' . '/nette/utils/src/Utils/Image.php', + 'Nette\\Utils\\ImageColor' => __DIR__ . '/..' . '/nette/utils/src/Utils/ImageColor.php', + 'Nette\\Utils\\ImageException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ImageType' => __DIR__ . '/..' . '/nette/utils/src/Utils/ImageType.php', + 'Nette\\Utils\\Iterables' => __DIR__ . '/..' . '/nette/utils/src/Utils/Iterables.php', + 'Nette\\Utils\\Json' => __DIR__ . '/..' . '/nette/utils/src/Utils/Json.php', + 'Nette\\Utils\\JsonException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\ObjectHelpers' => __DIR__ . '/..' . '/nette/utils/src/Utils/ObjectHelpers.php', + 'Nette\\Utils\\Paginator' => __DIR__ . '/..' . '/nette/utils/src/Utils/Paginator.php', + 'Nette\\Utils\\Random' => __DIR__ . '/..' . '/nette/utils/src/Utils/Random.php', + 'Nette\\Utils\\Reflection' => __DIR__ . '/..' . '/nette/utils/src/Utils/Reflection.php', + 'Nette\\Utils\\ReflectionMethod' => __DIR__ . '/..' . '/nette/utils/src/Utils/ReflectionMethod.php', + 'Nette\\Utils\\RegexpException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Strings' => __DIR__ . '/..' . '/nette/utils/src/Utils/Strings.php', + 'Nette\\Utils\\Type' => __DIR__ . '/..' . '/nette/utils/src/Utils/Type.php', + 'Nette\\Utils\\UnknownImageFileException' => __DIR__ . '/..' . '/nette/utils/src/Utils/exceptions.php', + 'Nette\\Utils\\Validators' => __DIR__ . '/..' . '/nette/utils/src/Utils/Validators.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->prefixLengthsPsr4 = ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7::$prefixLengthsPsr4; + $loader->prefixDirsPsr4 = ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7::$prefixDirsPsr4; + $loader->classMap = ComposerStaticInitf9e7218f71d5874b5632927df4f72bd7::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/tools/.phpstan/vendor/composer/installed.json b/tools/.phpstan/vendor/composer/installed.json new file mode 100644 index 00000000000..bb0437ecfae --- /dev/null +++ b/tools/.phpstan/vendor/composer/installed.json @@ -0,0 +1,399 @@ +{ + "packages": [ + { + "name": "ergebnis/phpstan-rules", + "version": "2.12.0", + "version_normalized": "2.12.0.0", + "source": { + "type": "git", + "url": "https://github.com/ergebnis/phpstan-rules.git", + "reference": "c4e0121a937b3b551f800a86e7d78794da2783ea" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ergebnis/phpstan-rules/zipball/c4e0121a937b3b551f800a86e7d78794da2783ea", + "reference": "c4e0121a937b3b551f800a86e7d78794da2783ea", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "phpstan/phpstan": "^2.1.8" + }, + "require-dev": { + "codeception/codeception": "^4.0.0 || ^5.0.0", + "doctrine/orm": "^2.20.0 || ^3.3.0", + "ergebnis/composer-normalize": "^2.47.0", + "ergebnis/license": "^2.6.0", + "ergebnis/php-cs-fixer-config": "^6.54.0", + "ergebnis/phpunit-slow-test-detector": "^2.20.0", + "fakerphp/faker": "^1.24.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "phpunit/phpunit": "^9.6.21", + "psr/container": "^2.0.2", + "symfony/finder": "^5.4.45", + "symfony/process": "^5.4.47" + }, + "time": "2025-09-07T13:31:33+00:00", + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Ergebnis\\PHPStan\\Rules\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com/" + } + ], + "description": "Provides rules for phpstan/phpstan.", + "homepage": "https://github.com/ergebnis/phpstan-rules", + "keywords": [ + "PHPStan", + "phpstan-rules" + ], + "support": { + "issues": "https://github.com/ergebnis/phpstan-rules/issues", + "security": "https://github.com/ergebnis/phpstan-rules/blob/main/.github/SECURITY.md", + "source": "https://github.com/ergebnis/phpstan-rules" + }, + "install-path": "../ergebnis/phpstan-rules" + }, + { + "name": "nette/utils", + "version": "v4.1.0", + "version_normalized": "4.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "reference": "fa1f0b8261ed150447979eb22e373b7b7ad5a8e0", + "shasum": "" + }, + "require": { + "php": "8.2 - 8.5" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "^1.2", + "nette/tester": "^2.5", + "phpstan/phpstan-nette": "^2.0@stable", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "time": "2025-12-01T17:49:23+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.1-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Nette\\": "src" + }, + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com/" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org/", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.1.0" + }, + "install-path": "../nette/utils" + }, + { + "name": "phpstan/extension-installer", + "version": "1.4.3", + "version_normalized": "1.4.3.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/extension-installer.git", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/extension-installer/zipball/85e90b3942d06b2326fba0403ec24fe912372936", + "reference": "85e90b3942d06b2326fba0403ec24fe912372936", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.0", + "php": "^7.2 || ^8.0", + "phpstan/phpstan": "^1.9.0 || ^2.0" + }, + "require-dev": { + "composer/composer": "^2.0", + "php-parallel-lint/php-parallel-lint": "^1.2.0", + "phpstan/phpstan-strict-rules": "^0.11 || ^0.12 || ^1.0" + }, + "time": "2024-09-04T20:21:43+00:00", + "type": "composer-plugin", + "extra": { + "class": "PHPStan\\ExtensionInstaller\\Plugin" + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPStan\\ExtensionInstaller\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Composer plugin for automatic installation of PHPStan extensions", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "issues": "https://github.com/phpstan/extension-installer/issues", + "source": "https://github.com/phpstan/extension-installer/tree/1.4.3" + }, + "install-path": "../phpstan/extension-installer" + }, + { + "name": "phpstan/phpstan", + "version": "2.1.33", + "version_normalized": "2.1.33.0", + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan/zipball/9e800e6bee7d5bd02784d4c6069b48032d16224f", + "reference": "9e800e6bee7d5bd02784d4c6069b48032d16224f", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "time": "2025-12-05T10:24:31+00:00", + "bin": [ + "phpstan", + "phpstan.phar" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "files": [ + "bootstrap.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "PHPStan - PHP Static Analysis Tool", + "keywords": [ + "dev", + "static analysis" + ], + "support": { + "docs": "https://phpstan.org/user-guide/getting-started", + "forum": "https://github.com/phpstan/phpstan/discussions", + "issues": "https://github.com/phpstan/phpstan/issues", + "security": "https://github.com/phpstan/phpstan/security/policy", + "source": "https://github.com/phpstan/phpstan-src" + }, + "funding": [ + { + "url": "https://github.com/ondrejmirtes", + "type": "github" + }, + { + "url": "https://github.com/phpstan", + "type": "github" + } + ], + "install-path": "../phpstan/phpstan" + }, + { + "name": "phpstan/phpstan-strict-rules", + "version": "2.0.7", + "version_normalized": "2.0.7.0", + "source": { + "type": "git", + "url": "https://github.com/phpstan/phpstan-strict-rules.git", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phpstan/phpstan-strict-rules/zipball/d6211c46213d4181054b3d77b10a5c5cb0d59538", + "reference": "d6211c46213d4181054b3d77b10a5c5cb0d59538", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.29" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "time": "2025-09-26T11:19:08+00:00", + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Extra strict and opinionated rules for PHPStan", + "support": { + "issues": "https://github.com/phpstan/phpstan-strict-rules/issues", + "source": "https://github.com/phpstan/phpstan-strict-rules/tree/2.0.7" + }, + "install-path": "../phpstan/phpstan-strict-rules" + }, + { + "name": "tomasvotruba/type-coverage", + "version": "2.1.0", + "version_normalized": "2.1.0.0", + "source": { + "type": "git", + "url": "https://github.com/TomasVotruba/type-coverage.git", + "reference": "468354b3964120806a69890cbeb3fcf005876391" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/TomasVotruba/type-coverage/zipball/468354b3964120806a69890cbeb3fcf005876391", + "reference": "468354b3964120806a69890cbeb3fcf005876391", + "shasum": "" + }, + "require": { + "nette/utils": "^3.2 || ^4.0", + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0" + }, + "time": "2025-12-05T16:38:02+00:00", + "type": "phpstan-extension", + "extra": { + "phpstan": { + "includes": [ + "config/extension.neon" + ] + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "TomasVotruba\\TypeCoverage\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Measure type coverage of your project", + "keywords": [ + "phpstan-extension", + "static analysis" + ], + "support": { + "issues": "https://github.com/TomasVotruba/type-coverage/issues", + "source": "https://github.com/TomasVotruba/type-coverage/tree/2.1.0" + }, + "funding": [ + { + "url": "https://www.paypal.me/rectorphp", + "type": "custom" + }, + { + "url": "https://github.com/tomasvotruba", + "type": "github" + } + ], + "install-path": "../tomasvotruba/type-coverage" + } + ], + "dev": true, + "dev-package-names": [ + "ergebnis/phpstan-rules", + "nette/utils", + "phpstan/extension-installer", + "phpstan/phpstan", + "phpstan/phpstan-strict-rules", + "tomasvotruba/type-coverage" + ] +} diff --git a/tools/.phpstan/vendor/composer/installed.php b/tools/.phpstan/vendor/composer/installed.php new file mode 100644 index 00000000000..0adbcfad6db --- /dev/null +++ b/tools/.phpstan/vendor/composer/installed.php @@ -0,0 +1,77 @@ + array( + 'name' => '__root__', + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '0f3c5191011dcc67167d3013fde9951f65b1453f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev' => true, + ), + 'versions' => array( + '__root__' => array( + 'pretty_version' => 'dev-main', + 'version' => 'dev-main', + 'reference' => '0f3c5191011dcc67167d3013fde9951f65b1453f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../../', + 'aliases' => array(), + 'dev_requirement' => false, + ), + 'ergebnis/phpstan-rules' => array( + 'pretty_version' => '2.12.0', + 'version' => '2.12.0.0', + 'reference' => 'c4e0121a937b3b551f800a86e7d78794da2783ea', + 'type' => 'phpstan-extension', + 'install_path' => __DIR__ . '/../ergebnis/phpstan-rules', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'nette/utils' => array( + 'pretty_version' => 'v4.1.0', + 'version' => '4.1.0.0', + 'reference' => 'fa1f0b8261ed150447979eb22e373b7b7ad5a8e0', + 'type' => 'library', + 'install_path' => __DIR__ . '/../nette/utils', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'phpstan/extension-installer' => array( + 'pretty_version' => '1.4.3', + 'version' => '1.4.3.0', + 'reference' => '85e90b3942d06b2326fba0403ec24fe912372936', + 'type' => 'composer-plugin', + 'install_path' => __DIR__ . '/../phpstan/extension-installer', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'phpstan/phpstan' => array( + 'pretty_version' => '2.1.33', + 'version' => '2.1.33.0', + 'reference' => '9e800e6bee7d5bd02784d4c6069b48032d16224f', + 'type' => 'library', + 'install_path' => __DIR__ . '/../phpstan/phpstan', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'phpstan/phpstan-strict-rules' => array( + 'pretty_version' => '2.0.7', + 'version' => '2.0.7.0', + 'reference' => 'd6211c46213d4181054b3d77b10a5c5cb0d59538', + 'type' => 'phpstan-extension', + 'install_path' => __DIR__ . '/../phpstan/phpstan-strict-rules', + 'aliases' => array(), + 'dev_requirement' => true, + ), + 'tomasvotruba/type-coverage' => array( + 'pretty_version' => '2.1.0', + 'version' => '2.1.0.0', + 'reference' => '468354b3964120806a69890cbeb3fcf005876391', + 'type' => 'phpstan-extension', + 'install_path' => __DIR__ . '/../tomasvotruba/type-coverage', + 'aliases' => array(), + 'dev_requirement' => true, + ), + ), +); diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/CHANGELOG.md b/tools/.phpstan/vendor/ergebnis/phpstan-rules/CHANGELOG.md new file mode 100644 index 00000000000..7729147afef --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/CHANGELOG.md @@ -0,0 +1,748 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## Unreleased + +For a full diff see [`2.12.0...main`][2.12.0...main]. + +## [`2.12.0`][2.12.0] + +For a full diff see [`2.11.0...2.12.0`][2.11.0...2.12.0]. + +### Added + +- Added support for PHP 8.5 ([#977]), by [@localheinz] + +## [`2.11.0`][2.11.0] + +For a full diff see [`2.10.5...2.11.0`][2.10.5...2.11.0]. + +### Changed + +- Allowed installation on PHP 8.5 ([#972]), by [@localheinz] + +## [`2.10.5`][2.10.5] + +For a full diff see [`2.10.4...2.10.5`][2.10.4...2.10.5]. + +### Fixed + +- Adjusted `Methods\NoNamedArgumentRule` to handle calls to constructors of variable class names ([#957]), by [@localheinz] +- Adjusted `Methods\NoNamedArgumentRule` to describe known calls only ([#958]), by [@localheinz] + +## [`2.10.4`][2.10.4] + +For a full diff see [`2.10.3...2.10.4`][2.10.3...2.10.4]. + +### Fixed + +- Adjusted `Methods\NoNamedArgumentRule` to handle static calls on variable expressions ([#947]), by [@localheinz] +- Adjusted `Methods\NoNamedArgumentRule` to handle calls on invokables ([#948]), by [@localheinz] +- Adjusted `Methods\NoNamedArgumentRule` to handle calls on callables assigned to properties ([#949]), by [@localheinz] +- Adjusted `Methods\NoNamedArgumentRule` to handle all other calls with generic error message ([#951]), by [@localheinz] + +## [`2.10.3`][2.10.3] + +For a full diff see [`2.10.2...2.10.3`][2.10.2...2.10.3]. + +### Fixed + +- Adjusted `Methods\InvokeParentHookMethodRule` to ignore comments ([#944]), by [@localheinz] + +## [`2.10.2`][2.10.2] + +For a full diff see [`2.10.1...2.10.2`][2.10.1...2.10.2]. + +### Fixed + +- Renamed error identifier for `Methods\InvokeParentHookMethodRule` ([#943]), by [@localheinz] + +## [`2.10.1`][2.10.1] + +For a full diff see [`2.10.0...2.10.1`][2.10.0...2.10.1]. + +### Fixed + +- Fixed schema for configuration of `Methods\InvokeParentHookMethodRule` ([#940]), by [@localheinz] + +## [`2.10.0`][2.10.0] + +For a full diff see [`2.9.0...2.10.0`][2.9.0...2.10.0]. + +### Added + +- Added `Methods\InvokeParentHookMethodRule`, which reports an error when a hook method that overrides a hook method in a parent class does not invoke the overridden hook method in the expected order ([#939]), by [@localheinz] + +## [`2.9.0`][2.9.0] + +For a full diff see [`2.8.0...2.9.0`][2.8.0...2.9.0]. + +### Added + +- Added `CallLikes\NoNamedArgumentRule`, which reports an error when an anonymous function, a function, or a method is invoked using a named argument ([#914]), by [@localheinz] + +### Changed + +- Required `phpstan/phpstan:^2.1.8` ([#938]), by [@localheinz] + +## [`2.8.0`][2.8.0] + +For a full diff see [`2.7.0...2.8.0`][2.7.0...2.8.0]. + +### Added + +- Added `allRules` parameter to allow disabling and enabling all rules ([#913]), by [@localheinz] +- Added `Expressions\NoAssignByReferenceRule`, which reports an error when a variable is assigned by reference ([#914]), by [@localheinz] + +## [`2.7.0`][2.7.0] + +For a full diff see [`2.6.1...2.7.0`][2.6.1...2.7.0]. + +### Added + +- Added `Closures\NoParameterPassedByReferenceRule`, `Functions\NoParameterPassedByReferenceRule`, `Methods\NoParameterPassedByReferenceRule`, which report an error when a closure, a function, or a method has a parameter that is passed by reference ([#911]), by [@localheinz] +- Added `Functions\NoReturnByReferenceRule` and `Methods\NoReturnByReferenceRule`, which report an error when a function or a method returns by reference ([#912]), by [@localheinz] + +## [`2.6.1`][2.6.1] + +For a full diff see [`2.6.0...2.6.1`][2.6.0...2.6.1]. + +### Fixed + +- Adjusted `Methods\NoParameterWithNullableTypeDeclarationRule` to use the appropriate error identifier ([#902]), by [@manuelkiessling] + +## [`2.6.0`][2.6.0] + +For a full diff see [`2.5.2...2.6.0`][2.5.2...2.6.0]. + +### Added + +- Added support for `phpstan/phpstan:^2.0.0` ([#873]), by [@localheinz] + +## [`2.5.2`][2.5.2] + +For a full diff see [`2.5.1...2.5.2`][2.5.1...2.5.2]. + +### Fixed + +- Adjusted `Closures\NoNullableReturnTypeDeclarationRule`, `Closures\NoParameterWithNullableTypeDeclarationRule`, `Functions\NoNullableReturnTypeDeclarationRule`, `Functions\NoParameterWithNullableTypeDeclarationRule`, `Methods\NoNullableReturnTypeDeclarationRule`, `Methods\NoParameterWithNullableTypeDeclarationRule` to detect cases where `null` is referenced with incorrect case or relative to the root namespace ([#897]), by [@localheinz] + +## [`2.5.1`][2.5.1] + +For a full diff see [`2.5.0...2.5.1`][2.5.0...2.5.1]. + +### Fixed + +- Returned rule with error identifier ([#882]), by [@localheinz] +- Adjusted `Methods\FinalInAbstractClassRule` to ignore Doctrine embeddables and entities ([#396]), by [@localheinz] +- Adjusted `Expressions\NoCompactRule` to detect usages of `compact()` with incorrect case ([#889]), by [@localheinz] +- Adjusted `Methods\PrivateInFinalClassRule` to use more appropriate message when detecting a `protected` method in an anonymous class ([#890]), by [@localheinz] +- Adjusted `Methods\PrivateInFinalClassRule` to ignore `protected` methods from traits ([#891]), by [@localheinz] +- Adjusted `Methods\PrivateInFinalClassRule` to ignore `protected` methods with `phpunit/phpunit` attributes requiring methods to be `protected` ([#863]), by [@cosmastech] +- Adjusted `Methods\PrivateInFinalClassRule` to ignore `protected` methods with `phpunit/phpunit` annotations requiring methods to be `protected` ([#895]), by [@cosmastech] + +## [`2.5.0`][2.5.0] + +For a full diff see [`2.4.0...2.5.0`][2.4.0...2.5.0]. + +### Added + +- Added rule error identifiers ([#875]), by [@localheinz] +- Added support for PHP 8.0 ([#877]), by [@localheinz] +- Added support for PHP 7.4 ([#880]), by [@localheinz] + +### Changed + +- Removed dependency on `nikic/php-parser` ([#878]), by [@localheinz] + +## [`2.4.0`][2.4.0] + +For a full diff see [`2.3.0...2.4.0`][2.3.0...2.4.0]. + +### Added + +- Added support for PHP 8.4 ([#872]), by [@localheinz] + +## [`2.3.0`][2.3.0] + +For a full diff see [`2.2.0...2.3.0`][2.2.0...2.3.0]. + +### Changed + +- Allowed installation on PHP 8.4 ([#862]), by [@localheinz] + +## [`2.2.0`][2.2.0] + +For a full diff see [`2.1.0...2.2.0`][2.1.0...2.2.0]. + +### Changed + +- Allowed installation of `nikic/php-parser:^5.0.0` ([#735]), by [@localheinz] + +## [`2.1.0`][2.1.0] + +For a full diff see [`2.0.0...2.1.0`][2.0.0...2.1.0]. + +### Changed + +- Dropped support for PHP 8.0 ([#567]), by [@localheinz] +- Added support for PHP 8.3 ([#604]), by [@nunomaduro] + +## [`2.0.0`][2.0.0] + +For a full diff see [`1.0.0...2.0.0`][1.0.0...2.0.0]. + +### Added + +- Added `methodsAllowedToUseContainerTypeDeclarations` parameter to allow configuring a list of method names that are allowed to have container parameter type declarations ([#541), by [@localheinz] +- Allowed disabling rules ([#542), by [@localheinz] +- Added support for nullable union types ([#543), by [@localheinz] + +### Changed + +- Dropped support for PHP 7.2 ([#496]), by [@localheinz] +- Dropped support for PHP 7.3 ([#498]), by [@localheinz] +- Dropped support for PHP 7.4 ([#499]), by [@localheinz] +- Added support for PHP 8.2 ([#540]), by [@localheinz] + +### Removed + +- Removed `Expressions\NoEmptyRule` ([#525]), by [@enumag] + +## [`1.0.0`][1.0.0] + +For a full diff see [`0.15.3...1.0.0`][0.15.3...1.0.0]. + +### Changed + +- Added support for `phpstan/phpstan:^1.0.0` and dropped support for non-stable versions of `phpstan/phpstan` ([#381]), by [@rpkamp] + +### Fixed + +- Adjusted `Classes\FinalRule` to not report an error when a non-final class has a `Doctrinbe\ORM\Mapping\Entity` attribute ([#395]), by [@localheinz] + +## [`0.15.3`][0.15.3] + +For a full diff see [`0.15.2...0.15.3`][0.15.2...0.15.3]. + +### Changed + +- Allow installation with PHP 8.0 ([#294]), by [@localheinz] + +## [`0.15.2`][0.15.2] + +For a full diff see [`0.15.1...0.15.2`][0.15.1...0.15.2]. + +### Changed + +- Dropped support for PHP 7.1 ([#259]), by [@localheinz] + +## [`0.15.1`][0.15.1] + +For a full diff see [`0.15.0...0.15.1`][0.15.0...0.15.1]. + +### Changed + +- Adjusted `Methods\FinalInAbstractClass` rule to allow non-`final` `public` constructors in abstract classes ([#248]), by [@Slamdunk] + +## [`0.15.0`][0.15.0] + +For a full diff see [`0.14.4...0.15.0`][0.14.4...0.15.0]. + +### Added + +- Added `Classes\PHPUnit\Framework\TestCaseWithSuffixRule`, which reports an error when a concrete class extending `PHPUnit\Framework\TestCase` does not have a `Test` suffix ([#225]), by [@localheinz] + +## [`0.14.4`][0.14.4] + +For a full diff see [`0.14.3...0.14.4`][0.14.3...0.14.4]. + +### Fixed + +- Ignored classes with `@ORM\Mapping\Entity` annotations in `FinalRule` ([#202]), by [@localheinz] + +## [`0.14.3`][0.14.3] + +For a full diff see [`0.14.2...0.14.3`][0.14.2...0.14.3]. + +### Fixed + +- Ignored first line in `DeclareStrictTypesRule` when it is a shebang ([#186]), by [@Great-Antique] + +## [`0.14.2`][0.14.2] + +For a full diff see [`0.14.1...0.14.2`][0.14.1...0.14.2]. + +### Fixed + +- Brought back support for PHP 7.1 ([#166]), by [@localheinz] + +## [`0.14.1`][0.14.1] + +For a full diff see [`0.14.0...0.14.1`][0.14.0...0.14.1]. + +### Fixed + +- Removed an inappropriate `replace` configuration from `composer.json` ([#161]), by [@localheinz] + +## [`0.14.0`][0.14.0] + +For a full diff see [`0.13.0...0.14.0`][0.13.0...0.14.0]. + +### Changed + +- Allowed installation of `phpstan/phpstan:~0.12.0` ([#147]), by [@localheinz] +- Renamed vendor namespace `Localheinz` to `Ergebnis` after move to [@ergebnis] ([#157]), by [@localheinz] + + Run + + ```sh + composer remove localheinz/phpstan-rules + ``` + + and + + ```sh + composer require ergebnis/phpstan-rules + ``` + + to update. + + Run + + ```sh + find . -type f -exec sed -i '.bak' 's/Localheinz\\PHPStan/Ergebnis\\PHPStan/g' {} \; + ``` + + to replace occurrences of `Localheinz\PHPStan` with `Ergebnis\PHPStan`. + + Run + + ```sh + find -type f -name '*.bak' -delete + ``` + + to delete backup files created in the previous step. + +- Moved parameters into `ergebnis` section to prevent conflicts with global parameters ([#158]), by [@localheinz] + + Where previously `phpstan.neon` looked like the following + + ```neon + parameters: + allowAbstractClasses: true + classesAllowedToBeExtended: [] + classesNotRequiredToBeAbstractOrFinal: [] + interfacesImplementedByContainers: + - Psr\Container\ContainerInterface + ``` + + these parameters now need to be moved into an `ergebnis` section: + + ```diff + parameters: + - allowAbstractClasses: true + - classesAllowedToBeExtended: [] + - classesNotRequiredToBeAbstractOrFinal: [] + - interfacesImplementedByContainers: + - - Psr\Container\ContainerInterface + + ergebnis: + + allowAbstractClasses: true + + classesAllowedToBeExtended: [] + + classesNotRequiredToBeAbstractOrFinal: [] + + interfacesImplementedByContainers: + + - Psr\Container\ContainerInterface + ``` + +### Fixed + +- Dropped support for PHP 7.1 ([#141]), by [@localheinz] + +## [`0.13.0`][0.13.0] + +For a full diff see [`0.12.2...0.13.0`][0.12.2...0.13.0]. + +### Added + +- Added `Methods\PrivateInFinalClassRule` which reports an error when a method in a `final` class is `protected` when it could be `private` ([#126]), by [@localheinz] + +## [`0.12.2`][0.12.2] + +For a full diff see [`0.12.1...0.12.2`][0.12.1...0.12.2]. + +### Fixed + +- Started ignoring interfaces from analysis by `Methods\FinalInAbstractClassRule` to avoid inappropriate errors ([#132]), by [@localheinz] + +## [`0.12.1`][0.12.1] + +For a full diff see [`0.12.0...0.12.1`][0.12.0...0.12.1]. + +### Fixed + +- Started resolving class name in type declaration before attempting to analyze it in the `Methods\NoParameterWithContainerTypeDeclarationRule` to avoid errors where class `self` is not found ([#128]), by [@localheinz] + +## [`0.12.0`][0.12.0] + +For a full diff see [`0.11.0...0.12.0`][0.11.0...0.12.0]. + +### Added + +- Added `Methods\NoParameterWithContainerTypeDeclarationRule`, which reports an error when a method has a type declaration that corresponds to a known dependency injection container or service locator ([#122]), by [@localheinz] +- Added `Methods\FinalInAbstractClassRule`, which reports an error when a concrete `public` or `protected` method in an `abstract` class is not `final` ([#123]), by [@localheinz] + +## [`0.11.0`][0.11.0] + +For a full diff see [`0.10.0...0.11.0`][0.10.0...0.11.0]. + +### Added + +- Added `Files\DeclareStrictTypesRule`, which reports an error when a PHP file does not have a `declare(strict_types=1)` declaration ([#79] +- Added `Expressions\NoEmptyRule`, which reports an error when the language construct `empty()` is used ([#110]), by [@localheinz] +- Added `Expressions\NoEvalRule`, which reports an error when the language construct `eval()` is used ([#112]), by [@localheinz] +- Added `Expressions\NoErrorSuppressionRule`, which reports an error when `@` is used to suppress errors ([#113]), by [@localheinz] +- Added `Expressions\NoCompactRule`, which reports an error when the function `compact()` is used ([#116]), by [@localheinz] +- Added `Statements\NoSwitchRule`, which reports an error when the statement `switch()` is used ([#117]), by [@localheinz] + +### Changed + +- Require at least `nikic/php-parser:^4.2.3` ([#102]), by [@localheinz] +- Require at least `phpstan/phpstan:~0.11.15` ([#103]), by [@localheinz] + +## [`0.10.0`][0.10.0] + +For a full diff see [`0.9.1...0.10.0`][0.9.1...0.10.0]. + +### Changed + +- Require at least `phpstan/phpstan:~0.11.7` ([#91]), by [@localheinz] + +### Fixed + +- Added missing `parametersSchema` configuration to `rules.neon`, which is required for use with `bleedingEdge.neon`, see [`phpstan/phpstan@54a125d`](https://github.com/phpstan/phpstan/commit/54a125df47fa097b792cb9a3e70c49f753f66b85) ([#93]), by [@localheinz] +* +## [`0.9.1`][0.9.1] + +For a full diff see [`0.9.0...0.9.1`][0.9.0...0.9.1]. + +### Changed + +- Allow usage with [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer) ([#89]), by [@localheinz] + +## [`0.9.0`][0.9.0] + +For a full diff see [`0.8.1...0.9.0`][0.8.1...0.9.0]. + +### Changed + +- Adjusted `Classes\FinalRule` to ignore Doctrine entities when they are annotated ([#84]), by [@localheinz] + +## [`0.8.1`][0.8.1] + +For a full diff see [`0.8.0...0.8.1`][0.8.0...0.8.1]. + +### Fixed + +- Actually enable `Expressions\NoIssetRule` ([#83]), by [@localheinz] + +## [`0.8.0`][0.8.0] + +For a full diff see [`0.7.1...0.8.0`][0.7.1...0.8.0]. + +### Added + +- Added `Expressions\NoIssetRule`, which reports an error when the language construct `isset()` is used ([#81]), by [@localheinz] + +## [`0.7.1`][0.7.1] + +For a full diff see [`0.7.0...0.7.1`][0.7.0...0.7.1]. + +### Changed + +- Configured `Classes\NoExtendsRule` to allow a set of default classes to be extended ([#73]), by [@localheinz] + +## [`0.7.0`][0.7.0] + +For a full diff see [`0.6.0...0.7.0`][0.6.0...0.7.0]. + +### Added + +- Added `Classes\NoExtendsRule`, which reports an error when a class extends a class that is not allowed to be extended ([#68]), by [@localheinz] + +## [`0.6.0`][0.6.0] + +For a full diff see [`0.5.0...0.6.0`][0.5.0...0.6.0]. + +### Added + +- Allow installation with `phpstan/phpstan:~0.11.0` ([#65]), by [@localheinz] + +## [`0.5.0`][0.5.0] + +For a full diff see [`0.4.0...0.5.0`][0.4.0...0.5.0]. + +### Added + +- Added `Methods\NoConstructorParameterWithDefaultValueRule`, which reports an error when a constructor of an anonymous class or a class has a parameter with a default value ([#45]), by [@localheinz] +- Added parameters `$allowAbstractClasses` and `$classesNotRequiredToBeAbstractOrFinal` to allow configuration of `Classes`FinalRule` ([#51]), by [@localheinz] + +### Removed + +- Removed `Classes\AbstractOrFinalRule` after merging behaviour into `Classes\FinalRule` ([#51]), by [@localheinz] +- Removed default values from constructor of `Classes\FinalRule` ([#53]), by [@localheinz] + +## [`0.4.0`][0.4.0] + +For a full diff see [`0.3.0...0.4.0`][0.3.0...0.4.0] + +### Changed + +- Removed double-quotes from error messages to be more consistent with error messages generated by `phpstan/phstan` ([#39]), by [@localheinz] +- Modified wording and placement of method, function, and parameter names in error messages to be more consistent with error messages generated by `phpstan/phstan` ([#42]), by [@localheinz] + +## [`0.3.0`][0.3.0] + +For a full diff see [`0.2.0...0.3.0`][0.2.0...0.3.0] + +### Added + +- Added `Functions\NoNullableReturnTypeDeclarationRule`, which reports an error when a function has a nullable return type declaration, and `Methods\NoNullableReturnTypeDeclarationRule`, which reports an error when a method declared in an anonymous class, a class, or an interface has a nullable return type declaration ([#16]), by [@localheinz] +- Added `Closures\NoParameterWithNullDefaultValueRule`, which reports an error when a closure has a parameter with `null` as default value ([#26]), by [@localheinz] +- Added `Closures\NoNullableReturnTypeDeclarationRule`, which reports an error when a closure has a nullable return type declaration ([#29]), by [@localheinz] +- Added `Functions\NoParameterWithNullDefaultValueRule`, which reports an error when a function has a parameter with `null` as default value ([#31]), by [@localheinz] +- Added `Methods\NoParameterWithNullDefaultValueRule`, which reports an error when a method declared in an anonymous class, a class, or an interface has a parameter with `null` as default value ([#32]), by [@localheinz] +- Added `Closures\NoParameterWithNullableTypeDeclarationRule`, which reports an error when a closure has a parameter with a nullable type declaration ([#33]), by [@localheinz] +- Added `Functions\NoParameterWithNullableTypeDeclarationRule`, which reports an error when a function has a parameter with a nullable type declaration ([#34]), by [@localheinz] +- Added `Methods\NoParameterWithNullableTypeDeclarationRule`, which reports an error when a method declared in an anonymous class, a class, or an interface has a parameter with a nullable type declaration ([#35]), by [@localheinz] +- Extracted `rules.neon`, so you can easily enable all rules by including it in your `phpstan.neon` ([#37]), by [@localheinz] + +## [`0.2.0`][0.2.0] + +For a full diff see [`0.1.0...0.2.0`][0.1.0...0.2.0] + +### Added + +- Added `Classes\FinalRule`, which reports an error when a non-anonymous class is not `final`, ([#4]), by [@localheinz] + +### Changed + +- Added an `$excludeClassNames` argument to the constructors of `Classes\AbstractOrFinalRule` and `Classes\FinalRule` to allow whitelisting of classes, ([#11]), by [@localheinz] + +## [`0.1.0`][0.1.0] + +For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0]. + +### Added + +- Added `Classes\AbstractOrFinalRule`, which reports an error when a non-anonymous class is neither `abstract` nor `final`, ([#1]), by [@localheinz] + +[0.1.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.1.0 +[0.2.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.2.0 +[0.3.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.3.0 +[0.4.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.4.0 +[0.5.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.5.0 +[0.6.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.6.0 +[0.7.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.7.0 +[0.7.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.7.1 +[0.8.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.8.0 +[0.8.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.8.1 +[0.9.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.9.0 +[0.9.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.9.1 +[0.10.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.10.0 +[0.11.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.11.0 +[0.12.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.12.0 +[0.12.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.12.1 +[0.12.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.12.2 +[0.13.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.13.0 +[0.14.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.14.0 +[0.14.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.14.1 +[0.14.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.14.2 +[0.14.3]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.14.3 +[0.14.4]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.14.4 +[0.15.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.15.0 +[0.15.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.15.1 +[0.15.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.15.2 +[0.15.3]: https://github.com/ergebnis/phpstan-rules/releases/tag/0.15.3 +[1.0.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/1.0.0 +[2.0.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.0.0 +[2.1.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.1.0 +[2.2.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.2.0 +[2.3.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.3.0 +[2.4.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.4.0 +[2.5.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.5.0 +[2.5.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.5.1 +[2.5.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.5.2 +[2.6.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.6.0 +[2.6.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.6.1 +[2.7.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.7.0 +[2.8.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.8.0 +[2.9.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.9.0 +[2.10.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.0 +[2.10.1]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.1 +[2.10.2]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.2 +[2.10.3]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.3 +[2.10.4]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.4 +[2.10.5]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.10.5 +[2.11.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.11.0 +[2.12.0]: https://github.com/ergebnis/phpstan-rules/releases/tag/2.12.0 + +[362c7ea...0.1.0]: https://github.com/ergebnis/phpstan-rules/compare/362c7ea...0.1.0 +[0.1.0...0.2.0]: https://github.com/ergebnis/phpstan-rules/compare/0.1.0...0.2.0 +[0.2.0...0.3.0]: https://github.com/ergebnis/phpstan-rules/compare/0.2.0...0.3.0 +[0.3.0...0.4.0]: https://github.com/ergebnis/phpstan-rules/compare/0.3.0...0.4.0 +[0.4.0...0.5.0]: https://github.com/ergebnis/phpstan-rules/compare/0.4.0...0.5.0 +[0.5.0...0.6.0]: https://github.com/ergebnis/phpstan-rules/compare/0.5.0...0.6.0 +[0.6.0...0.7.0]: https://github.com/ergebnis/phpstan-rules/compare/0.6.0...0.7.0 +[0.7.0...0.7.1]: https://github.com/ergebnis/phpstan-rules/compare/0.7.0...0.7.1 +[0.7.1...0.8.0]: https://github.com/ergebnis/phpstan-rules/compare/0.7.1...0.8.0 +[0.8.0...0.8.1]: https://github.com/ergebnis/phpstan-rules/compare/0.8.0...0.8.1 +[0.8.1...0.9.0]: https://github.com/ergebnis/phpstan-rules/compare/0.8.1...0.9.0 +[0.9.0...0.9.1]: https://github.com/ergebnis/phpstan-rules/compare/0.9.0...0.9.1 +[0.9.1...0.10.0]: https://github.com/ergebnis/phpstan-rules/compare/0.9.1...0.10.0 +[0.10.0...0.11.0]: https://github.com/ergebnis/phpstan-rules/compare/0.10.0...0.11.0 +[0.11.0...0.12.0]: https://github.com/ergebnis/phpstan-rules/compare/0.11.0...0.12.0 +[0.12.0...0.12.1]: https://github.com/ergebnis/phpstan-rules/compare/0.12.0...0.12.1 +[0.12.1...0.12.2]: https://github.com/ergebnis/phpstan-rules/compare/0.12.1...0.12.2 +[0.12.2...0.13.0]: https://github.com/ergebnis/phpstan-rules/compare/0.12.2...0.13.0 +[0.13.0...0.14.0]: https://github.com/ergebnis/phpstan-rules/compare/0.13.0...0.14.0 +[0.14.0...0.14.1]: https://github.com/ergebnis/phpstan-rules/compare/0.14.0...0.14.1 +[0.14.1...0.14.2]: https://github.com/ergebnis/phpstan-rules/compare/0.14.1...0.14.2 +[0.14.2...0.14.3]: https://github.com/ergebnis/phpstan-rules/compare/0.14.2...0.14.3 +[0.14.3...0.14.4]: https://github.com/ergebnis/phpstan-rules/compare/0.14.3...0.14.4 +[0.14.4...0.15.0]: https://github.com/ergebnis/phpstan-rules/compare/0.14.4...0.15.0 +[0.15.0...0.15.1]: https://github.com/ergebnis/phpstan-rules/compare/0.15.0...0.15.1 +[0.15.1...0.15.2]: https://github.com/ergebnis/phpstan-rules/compare/0.15.1...0.15.2 +[0.15.2...0.15.3]: https://github.com/ergebnis/phpstan-rules/compare/0.15.2...0.15.3 +[0.15.3...1.0.0]: https://github.com/ergebnis/phpstan-rules/compare/0.15.3...1.0.0 +[1.0.0...2.0.0]: https://github.com/ergebnis/phpstan-rules/compare/1.0.0...2.0.0 +[2.0.0...2.1.0]: https://github.com/ergebnis/phpstan-rules/compare/2.0.0...2.1.0 +[2.1.0...2.2.0]: https://github.com/ergebnis/phpstan-rules/compare/2.1.0...2.2.0 +[2.2.0...2.3.0]: https://github.com/ergebnis/phpstan-rules/compare/2.2.0...2.3.0 +[2.3.0...2.4.0]: https://github.com/ergebnis/phpstan-rules/compare/2.3.0...2.4.0 +[2.4.0...2.5.0]: https://github.com/ergebnis/phpstan-rules/compare/2.4.0...2.5.0 +[2.5.0...2.5.1]: https://github.com/ergebnis/phpstan-rules/compare/2.5.0...2.5.1 +[2.5.1...2.5.2]: https://github.com/ergebnis/phpstan-rules/compare/2.5.1...2.5.2 +[2.5.2...2.6.0]: https://github.com/ergebnis/phpstan-rules/compare/2.5.2...2.6.0 +[2.6.0...2.6.1]: https://github.com/ergebnis/phpstan-rules/compare/2.6.0...2.6.1 +[2.6.1...2.7.0]: https://github.com/ergebnis/phpstan-rules/compare/2.6.1...2.7.0 +[2.7.0...2.8.0]: https://github.com/ergebnis/phpstan-rules/compare/2.7.0...2.8.0 +[2.8.0...2.9.0]: https://github.com/ergebnis/phpstan-rules/compare/2.8.0...2.9.0 +[2.9.0...2.10.0]: https://github.com/ergebnis/phpstan-rules/compare/2.9.0...2.10.0 +[2.10.0...2.10.1]: https://github.com/ergebnis/phpstan-rules/compare/2.10.0...2.10.1 +[2.10.1...2.10.2]: https://github.com/ergebnis/phpstan-rules/compare/2.10.1...2.10.2 +[2.10.2...2.10.3]: https://github.com/ergebnis/phpstan-rules/compare/2.10.2...2.10.3 +[2.10.3...2.10.4]: https://github.com/ergebnis/phpstan-rules/compare/2.10.3...2.10.4 +[2.10.4...2.10.5]: https://github.com/ergebnis/phpstan-rules/compare/2.10.4...2.10.5 +[2.10.5...2.11.0]: https://github.com/ergebnis/phpstan-rules/compare/2.10.5...2.11.0 +[2.11.0...2.12.0]: https://github.com/ergebnis/phpstan-rules/compare/2.11.0...2.12.0 +[2.12.0...main]: https://github.com/ergebnis/phpstan-rules/compare/2.12.0...main + +[#1]: https://github.com/ergebnis/phpstan-rules/pull/1 +[#4]: https://github.com/ergebnis/phpstan-rules/pull/4 +[#11]: https://github.com/ergebnis/phpstan-rules/pull/11 +[#16]: https://github.com/ergebnis/phpstan-rules/pull/16 +[#26]: https://github.com/ergebnis/phpstan-rules/pull/26 +[#29]: https://github.com/ergebnis/phpstan-rules/pull/29 +[#31]: https://github.com/ergebnis/phpstan-rules/pull/31 +[#32]: https://github.com/ergebnis/phpstan-rules/pull/32 +[#33]: https://github.com/ergebnis/phpstan-rules/pull/33 +[#34]: https://github.com/ergebnis/phpstan-rules/pull/34 +[#35]: https://github.com/ergebnis/phpstan-rules/pull/35 +[#37]: https://github.com/ergebnis/phpstan-rules/pull/37 +[#39]: https://github.com/ergebnis/phpstan-rules/pull/39 +[#42]: https://github.com/ergebnis/phpstan-rules/pull/42 +[#45]: https://github.com/ergebnis/phpstan-rules/pull/45 +[#51]: https://github.com/ergebnis/phpstan-rules/pull/51 +[#53]: https://github.com/ergebnis/phpstan-rules/pull/53 +[#65]: https://github.com/ergebnis/phpstan-rules/pull/65 +[#68]: https://github.com/ergebnis/phpstan-rules/pull/68 +[#73]: https://github.com/ergebnis/phpstan-rules/pull/73 +[#79]: https://github.com/ergebnis/phpstan-rules/pull/79 +[#81]: https://github.com/ergebnis/phpstan-rules/pull/81 +[#83]: https://github.com/ergebnis/phpstan-rules/pull/83 +[#84]: https://github.com/ergebnis/phpstan-rules/pull/84 +[#89]: https://github.com/ergebnis/phpstan-rules/pull/89 +[#91]: https://github.com/ergebnis/phpstan-rules/pull/91 +[#93]: https://github.com/ergebnis/phpstan-rules/pull/93 +[#102]: https://github.com/ergebnis/phpstan-rules/pull/102 +[#103]: https://github.com/ergebnis/phpstan-rules/pull/103 +[#110]: https://github.com/ergebnis/phpstan-rules/pull/110 +[#112]: https://github.com/ergebnis/phpstan-rules/pull/112 +[#113]: https://github.com/ergebnis/phpstan-rules/pull/113 +[#116]: https://github.com/ergebnis/phpstan-rules/pull/116 +[#117]: https://github.com/ergebnis/phpstan-rules/pull/117 +[#122]: https://github.com/ergebnis/phpstan-rules/pull/122 +[#123]: https://github.com/ergebnis/phpstan-rules/pull/123 +[#126]: https://github.com/ergebnis/phpstan-rules/pull/126 +[#128]: https://github.com/ergebnis/phpstan-rules/pull/128 +[#132]: https://github.com/ergebnis/phpstan-rules/pull/132 +[#141]: https://github.com/ergebnis/phpstan-rules/pull/141 +[#147]: https://github.com/ergebnis/phpstan-rules/pull/147 +[#157]: https://github.com/ergebnis/phpstan-rules/pull/157 +[#158]: https://github.com/ergebnis/phpstan-rules/pull/158 +[#161]: https://github.com/ergebnis/phpstan-rules/pull/161 +[#166]: https://github.com/ergebnis/phpstan-rules/pull/166 +[#186]: https://github.com/ergebnis/phpstan-rules/pull/186 +[#202]: https://github.com/ergebnis/phpstan-rules/pull/202 +[#225]: https://github.com/ergebnis/phpstan-rules/pull/225 +[#248]: https://github.com/ergebnis/phpstan-rules/pull/248 +[#259]: https://github.com/ergebnis/phpstan-rules/pull/259 +[#294]: https://github.com/ergebnis/phpstan-rules/pull/294 +[#381]: https://github.com/ergebnis/phpstan-rules/pull/381 +[#395]: https://github.com/ergebnis/phpstan-rules/pull/395 +[#396]: https://github.com/ergebnis/phpstan-rules/pull/396 +[#496]: https://github.com/ergebnis/phpstan-rules/pull/496 +[#498]: https://github.com/ergebnis/phpstan-rules/pull/498 +[#499]: https://github.com/ergebnis/phpstan-rules/pull/498 +[#525]: https://github.com/ergebnis/phpstan-rules/pull/525 +[#540]: https://github.com/ergebnis/phpstan-rules/pull/540 +[#541]: https://github.com/ergebnis/phpstan-rules/pull/541 +[#542]: https://github.com/ergebnis/phpstan-rules/pull/542 +[#543]: https://github.com/ergebnis/phpstan-rules/pull/543 +[#567]: https://github.com/ergebnis/phpstan-rules/pull/567 +[#735]: https://github.com/ergebnis/phpstan-rules/pull/735 +[#862]: https://github.com/ergebnis/phpstan-rules/pull/862 +[#863]: https://github.com/ergebnis/phpstan-rules/pull/863 +[#872]: https://github.com/ergebnis/phpstan-rules/pull/872 +[#873]: https://github.com/ergebnis/phpstan-rules/pull/873 +[#875]: https://github.com/ergebnis/phpstan-rules/pull/875 +[#877]: https://github.com/ergebnis/phpstan-rules/pull/877 +[#878]: https://github.com/ergebnis/phpstan-rules/pull/878 +[#880]: https://github.com/ergebnis/phpstan-rules/pull/880 +[#882]: https://github.com/ergebnis/phpstan-rules/pull/882 +[#889]: https://github.com/ergebnis/phpstan-rules/pull/889 +[#890]: https://github.com/ergebnis/phpstan-rules/pull/890 +[#891]: https://github.com/ergebnis/phpstan-rules/pull/891 +[#895]: https://github.com/ergebnis/phpstan-rules/pull/895 +[#897]: https://github.com/ergebnis/phpstan-rules/pull/897 +[#902]: https://github.com/ergebnis/phpstan-rules/pull/902 +[#911]: https://github.com/ergebnis/phpstan-rules/pull/911 +[#912]: https://github.com/ergebnis/phpstan-rules/pull/912 +[#913]: https://github.com/ergebnis/phpstan-rules/pull/913 +[#914]: https://github.com/ergebnis/phpstan-rules/pull/914 +[#938]: https://github.com/ergebnis/phpstan-rules/pull/938 +[#939]: https://github.com/ergebnis/phpstan-rules/pull/939 +[#940]: https://github.com/ergebnis/phpstan-rules/pull/940 +[#943]: https://github.com/ergebnis/phpstan-rules/pull/943 +[#944]: https://github.com/ergebnis/phpstan-rules/pull/944 +[#947]: https://github.com/ergebnis/phpstan-rules/pull/947 +[#948]: https://github.com/ergebnis/phpstan-rules/pull/948 +[#949]: https://github.com/ergebnis/phpstan-rules/pull/949 +[#951]: https://github.com/ergebnis/phpstan-rules/pull/951 +[#957]: https://github.com/ergebnis/phpstan-rules/pull/957 +[#958]: https://github.com/ergebnis/phpstan-rules/pull/958 +[#972]: https://github.com/ergebnis/phpstan-rules/pull/972 +[#977]: https://github.com/ergebnis/phpstan-rules/pull/977 + +[@cosmastech]: https://github.com/cosmastech +[@enumag]: https://github.com/enumag +[@ergebnis]: https://github.com/ergebnis +[@Great-Antique]: https://github.com/Great-Antique +[@localheinz]: https://github.com/localheinz +[@manuelkiessling]: https://github.com/manuelkiessling +[@nunomaduro]: https://github.com/nunomaduro +[@rpkamp]: https://github.com/rpkamp +[@Slamdunk]: https://github.com/Slamdunk diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/LICENSE.md b/tools/.phpstan/vendor/ergebnis/phpstan-rules/LICENSE.md new file mode 100644 index 00000000000..130e719a290 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/LICENSE.md @@ -0,0 +1,16 @@ +# The MIT License (MIT) + +Copyright (c) 2018-2025 Andreas Möller + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated +documentation files (the _Software_), to deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the +Software. + +THE SOFTWARE IS PROVIDED **AS IS**, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/README.md b/tools/.phpstan/vendor/ergebnis/phpstan-rules/README.md new file mode 100644 index 00000000000..690d4ad0419 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/README.md @@ -0,0 +1,760 @@ +# phpstan-rules + +[![Integrate](https://github.com/ergebnis/phpstan-rules/workflows/Integrate/badge.svg)](https://github.com/ergebnis/phpstan-rules/actions) +[![Merge](https://github.com/ergebnis/phpstan-rules/workflows/Merge/badge.svg)](https://github.com/ergebnis/phpstan-rules/actions) +[![Release](https://github.com/ergebnis/phpstan-rules/workflows/Release/badge.svg)](https://github.com/ergebnis/phpstan-rules/actions) +[![Renew](https://github.com/ergebnis/phpstan-rules/workflows/Renew/badge.svg)](https://github.com/ergebnis/phpstan-rules/actions) + +[![Code Coverage](https://codecov.io/gh/ergebnis/phpstan-rules/branch/main/graph/badge.svg)](https://codecov.io/gh/ergebnis/phpstan-rules) + +[![Latest Stable Version](https://poser.pugx.org/ergebnis/phpstan-rules/v/stable)](https://packagist.org/packages/ergebnis/phpstan-rules) +[![Total Downloads](https://poser.pugx.org/ergebnis/phpstan-rules/downloads)](https://packagist.org/packages/ergebnis/phpstan-rules) +[![Monthly Downloads](http://poser.pugx.org/ergebnis/phpstan-rules/d/monthly)](https://packagist.org/packages/ergebnis/phpstan-rules) + +This project provides a [`composer`](https://getcomposer.org) package with rules for [`phpstan/phpstan`](https://github.com/phpstan/phpstan). + +## Installation + +Run + +```sh +composer require --dev ergebnis/phpstan-rules +``` + +## Usage + +All of the [rules](https://github.com/ergebnis/phpstan-rules#rules) provided (and used) by this library are included in [`rules.neon`](rules.neon). + +When you are using [`phpstan/extension-installer`](https://github.com/phpstan/extension-installer), `rules.neon` will be automatically included. + +Otherwise you need to include `rules.neon` in your `phpstan.neon`: + +```neon +includes: + - vendor/ergebnis/phpstan-rules/rules.neon +``` + +:bulb: You probably want to use these rules on top of the rules provided by: + +- [`phpstan/phpstan`](https://github.com/phpstan/phpstan) +- [`phpstan/phpstan-deprecation-rules`](https://github.com/phpstan/phpstan-deprecation-rules) +- [`phpstan/phpstan-strict-rules`](https://github.com/phpstan/phpstan-strict-rules) + +## Rules + +This package provides the following rules for use with [`phpstan/phpstan`](https://github.com/phpstan/phpstan): + +- [`Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule`](https://github.com/ergebnis/phpstan-rules#calllikesnonamedargumentrule) +- [`Ergebnis\PHPStan\Rules\Classes\FinalRule`](https://github.com/ergebnis/phpstan-rules#classesfinalrule) +- [`Ergebnis\PHPStan\Rules\Classes\NoExtendsRule`](https://github.com/ergebnis/phpstan-rules#classesnoextendsrule) +- [`Ergebnis\PHPStan\Rules\Classes\PHPUnit\Framework\TestCaseWithSuffixRule`](https://github.com/ergebnis/phpstan-rules#classesphpunitframeworktestcasewithsuffixrule) +- [`Ergebnis\PHPStan\Rules\Closures\NoNullableReturnTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#closuresnonullablereturntypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Closures\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterpassedbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterwithnullabletypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterwithnulldefaultvaluerule) +- [`Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoassignbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Expressions\NoCompactRule`](https://github.com/ergebnis/phpstan-rules#expressionsnocompactrule) +- [`Ergebnis\PHPStan\Rules\Expressions\NoErrorSuppressionRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoerrorsuppressionrule) +- [`Ergebnis\PHPStan\Rules\Expressions\NoEvalRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoevalrule) +- [`Ergebnis\PHPStan\Rules\Expressions\NoIssetRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoissetrule) +- [`Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule`](https://github.com/ergebnis/phpstan-rules#filesdeclarestricttypesrule) +- [`Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#functionsnonullablereturntypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Functions\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterpassedbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterwithnullabletypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#functionsnoparameterwithnulldefaultvaluerule) +- [`Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule`](https://github.com/ergebnis/phpstan-rules#functionsnoreturnbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule`](https://github.com/ergebnis/phpstan-rules#methodsfinalinabstractclassrule) +- [`Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule`](https://github.com/ergebnis/phpstan-rules#methodsinvokeparenthookmethodrule) +- [`Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#methodsnoconstructorparameterwithdefaultvaluerule) +- [`Ergebnis\PHPStan\Rules\Methods\NoNullableReturnTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#methodsnonullablereturntypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Methods\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#methodsnoparameterpassedbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Methods\NoParameterWithContainerTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#methodsnoparameterwithcontainertypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullableTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#methodsnoparameterwithnullabletypedeclarationrule) +- [`Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#methodsnoparameterwithnulldefaultvaluerule) +- [`Ergebnis\PHPStan\Rules\Methods\NoReturnByReferenceRule`](https://github.com/ergebnis/phpstan-rules#methodsnoreturnbyreferencerule) +- [`Ergebnis\PHPStan\Rules\Methods\PrivateInFinalClassRule`](https://github.com/ergebnis/phpstan-rules#methodsprivateinfinalclassrule) +- [`Ergebnis\PHPStan\Rules\Statements\NoSwitchRule`](https://github.com/ergebnis/phpstan-rules#statementsnoswitchrule) + + +### CallLikes + +#### `CallLikes\NoNamedArgumentRule` + +This rule reports an error when an anonymous function, a function, or a method is invoked using a [named argument](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noNamedArgument: + enabled: false +``` + +### Classes + +#### `Classes\FinalRule` + +This rule reports an error when a non-anonymous class is not `final`. + +:bulb: This rule ignores classes that + +- use `@Entity`, `@ORM\Entity`, or `@ORM\Mapping\Entity` annotations +- use `Doctrine\ORM\Mapping\Entity` attributes + +on the class level. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + final: + enabled: false +``` + +##### Disallowing `abstract` classes + +By default, this rule allows to declare `abstract` classes. + +You can set the `allowAbstractClasses` parameter to `false` to disallow abstract classes. + +```neon +parameters: + ergebnis: + final: + allowAbstractClasses: false +``` + +##### Excluding classes from inspection + +You can set the `classesNotRequiredToBeAbstractOrFinal` parameter to a list of class names that you want to exclude from inspection. + +```neon +parameters: + ergebnis: + final: + classesNotRequiredToBeAbstractOrFinal: + - Foo\Bar\NeitherAbstractNorFinal + - Bar\Baz\NeitherAbstractNorFinal +``` + +#### `Classes\NoExtendsRule` + +This rule reports an error when a class extends another class. + +##### Defaults + +By default, this rule allows the following classes to be extended: + +- [`PHPUnit\Framework\TestCase`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php) + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noExtends: + enabled: false +``` + +##### Allowing classes to be extended + +You can set the `classesAllowedToBeExtended` parameter to a list of class names that you want to allow to be extended. + +```neon +parameters: + ergebnis: + noExtends: + classesAllowedToBeExtended: + - Ergebnis\PHPStan\Rules\Test\Integration\AbstractTestCase + - Ergebnis\PHPStan\Rules\Test\Integration\AbstractTestCase +``` + +#### `Classes\PHPUnit\Framework\TestCaseWithSuffixRule` + +This rule reports an error when a concrete class is a sub-class of `PHPUnit\Framework\TestCase` but does not have a `Test` suffix. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + testCaseWithSuffix: + enabled: false +``` + +### Closures + +#### `Closures\NoNullableReturnTypeDeclarationRule` + +This rule reports an error when a closure uses a nullable return type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noNullableReturnTypeDeclaration: + enabled: false +``` + +#### `Closures\NoParameterPassedByReferenceRule` + +This rule reports an error when a closure has a parameter that is [passed by reference](https://www.php.net/manual/en/language.references.pass.php). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterPassedByReference: + enabled: false +``` + +#### `Closures\NoParameterWithNullableTypeDeclarationRule` + +This rule reports an error when a closure has a parameter with a nullable type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullableTypeDeclaration: + enabled: false +``` + +#### `Closures\NoParameterWithNullDefaultValueRule` + +This rule reports an error when a closure has a parameter with `null` as default value. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullDefaultValue: + enabled: false +``` + +### Expressions + +#### `Expressions\NoAssignByReferenceRule` + +This rule reports an error when [a variable is assigned by reference](https://www.php.net/manual/en/language.references.whatdo.php#language.references.whatdo.assign). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noAssignByReference: + enabled: false +``` + +#### `Expressions\NoCompactRule` + +This rule reports an error when the function [`compact()`](https://www.php.net/compact) is used. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noCompact: + enabled: false +``` + +#### `Expressions\NoErrorSuppressionRule` + +This rule reports an error when [`@`](https://www.php.net/manual/en/language.operators.errorcontrol.php) is used to suppress errors. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noErrorSuppression: + enabled: false +``` + +#### `Expressions\NoEvalRule` + +This rule reports an error when the language construct [`eval()`](https://www.php.net/eval) is used. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noEval: + enabled: false +``` + +#### `Expressions\NoIssetRule` + +This rule reports an error when the language construct [`isset()`](https://www.php.net/isset) is used. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noIsset: + enabled: false +``` + +### Files + +#### `Files\DeclareStrictTypesRule` + +This rule reports an error when a non-empty file does not contain a `declare(strict_types=1)` declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + declareStrictTypes: + enabled: false +``` + +### Functions + +#### `Functions\NoNullableReturnTypeDeclarationRule` + +This rule reports an error when a function uses a nullable return type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noNullableReturnTypeDeclaration: + enabled: false +``` + +#### `Functions\NoParameterPassedByReferenceRule` + +This rule reports an error when a function has a parameter that is [passed by reference](https://www.php.net/manual/en/language.references.pass.php). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterPassedByReference: + enabled: false +``` + +#### `Functions\NoParameterWithNullableTypeDeclarationRule` + +This rule reports an error when a function has a parameter with a nullable type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullableTypeDeclaration: + enabled: false +``` + +#### `Functions\NoParameterWithNullDefaultValueRule` + +This rule reports an error when a function has a parameter with `null` as default value. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullDefaultValue: + enabled: false +``` + +#### `Functions\NoReturnByReferenceRule` + +This rule reports an error when a function [returns by reference](https://www.php.net/manual/en/language.references.return.php). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noReturnByReference: + enabled: false +``` + +### Methods + +#### `Methods\FinalInAbstractClassRule` + +This rule reports an error when a concrete `public` or `protected` method in an `abstract` class is not `final`. + +:bulb: This rule ignores + +- Doctrine embeddables +- Doctrine entities + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + finalInAbstractClass: + enabled: false +``` + +#### `Methods\InvokeParentHookMethodRule` + +This rule reports an error when a hook method that overrides a hook method in a parent class does not invoke the overridden hook method in the expected order. + +##### Defaults + +By default, this rule requires the following hook methods to be invoked before doing something in the overriding method: + +- [`Codeception\PHPUnit\TestCase::_setUp()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L11-L13) +- [`Codeception\PHPUnit\TestCase::_setUpBeforeClass()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L25-L27) +- [`Codeception\Test\Unit::_before()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L63-L65) +- [`Codeception\Test\Unit::_setUp()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L34-L58) +- [`PHPUnit\Framework\TestCase::assertPreConditions()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2073-L2075) +- [`PHPUnit\Framework\TestCase::setUp()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2063-L2065) +- [`PHPUnit\Framework\TestCase::setUpBeforeClass()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2055-L2057) + +By default, this rule requires the following hook methods to be invoked after doing something in the overriding method: + +- [`Codeception\PHPUnit\TestCase::_tearDown()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L18-L20) +- [`Codeception\PHPUnit\TestCase::_tearDownAfterClass()`](https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L32-L34) +- [`Codeception\Test\Unit::_after()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L75-L77) +- [`Codeception\Test\Unit::_tearDown()`](https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L67-L70) +- [`PHPUnit\Framework\TestCase::assertPostConditions()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2083-L2085) +- [`PHPUnit\Framework\TestCase::tearDown()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2091-L2093) +- [`PHPUnit\Framework\TestCase::tearDownAfterClass()`](https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2098-L2100) + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + invokeParentHookMethod: + enabled: false +``` + +##### Configuring methods to invoke the parent method in the right order: + +You can set the `hookMethods` parameter to a list of hook methods: + +```neon +parameters: + ergebnis: + invokeParentHookMethod: + hookMethods: + - className: "Example\Test\Functional\AbstractCest" + methodName: "_before" + hasContent: "yes" + invocation: "first" +``` + +- `className`: name of the class that declares the hook method +- `methodName`: name of the hook method +- `hasContent`: one of `"yes"`, `"no"`, `"maybe"` +- `invocation`: one of `"any"` (needs to be invoked), `"first"` (needs to be invoked before all other statements in the overriding hook method, `"last"` (needs to be invoked after all other statements in the overriding hook method) + +#### `Methods\NoConstructorParameterWithDefaultValueRule` + +This rule reports an error when a constructor declared in + +- an anonymous class +- a class + +has a default value. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noConstructorParameterWithDefaultValue: + enabled: false +``` + +#### `Methods\NoParameterPassedByReferenceRule` + +This rule reports an error when a method has a parameter that is [passed by reference](https://www.php.net/manual/en/language.references.pass.php). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterPassedByReference: + enabled: false +``` + +#### `Methods\NoNullableReturnTypeDeclarationRule` + +This rule reports an error when a method declared in + +- an anonymous class +- a class +- an interface + +uses a nullable return type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noNullableReturnTypeDeclaration: + enabled: false +``` + +#### `Methods\NoParameterWithContainerTypeDeclarationRule` + +This rule reports an error when a method has a type declaration for a known dependency injection container or service locator. + +##### Defaults + +By default, this rule disallows the use of type declarations indicating an implementation of + +- [`Psr\Container\ContainerInterface`](https://github.com/php-fig/container/blob/1.0.0/src/ContainerInterface.php) + +is expected to be injected into a method. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithContainerTypeDeclaration: + enabled: false +``` + +##### Configuring container interfaces + +You can set the `interfacesImplementedByContainers` parameter to a list of interface names of additional containers and service locators. + +```neon +parameters: + ergebnis: + noParameterWithContainerTypeDeclaration: + interfacesImplementedByContainers: + - Fancy\DependencyInjection\ContainerInterface + - Other\ServiceLocatorInterface +``` + +##### Configuring methods allowed to use parameters with container type declarations + +You can set the `methodsAllowedToUseContainerTypeDeclarations` parameter to a list of method names that are allowed to use parameters with container type declarations. + +```neon +parameters: + ergebnis: + noParameterWithContainerTypeDeclaration: + methodsAllowedToUseContainerTypeDeclarations: + - loadExtension +``` + +#### `Methods\NoParameterWithNullableTypeDeclarationRule` + +This rule reports an error when a method declared in + +- an anonymous class +- a class +- an interface + +has a parameter with a nullable type declaration. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullableTypeDeclaration: + enabled: false +``` + +#### `Methods\NoParameterWithNullDefaultValueRule` + +This rule reports an error when a method declared in + +- an anonymous class +- a class +- an interface + +has a parameter with `null` as default value. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noParameterWithNullDefaultValue: + enabled: false +``` + +#### `Functions\NoReturnByReferenceRule` + +This rule reports an error when a method [returns by reference](https://www.php.net/manual/en/language.references.return.php). + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noReturnByReference: + enabled: false +``` + +#### `Methods\PrivateInFinalClassRule` + +This rule reports an error when a method in a `final` class is `protected` but could be `private`. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + privateInFinalClass: + enabled: false +``` + +### Statements + +#### `Statements\NoSwitchRule` + +This rule reports an error when the statement [`switch()`](https://www.php.net/manual/control-structures.switch.php) is used. + +##### Disabling the rule + +You can set the `enabled` parameter to `false` to disable this rule. + +```neon +parameters: + ergebnis: + noSwitch: + enabled: false +``` + +## Disabling all rules + +You can disable all rules using the `allRules` configuration parameter: + +```neon +parameters: + ergebnis: + allRules: false +``` + +## Enabling rules one-by-one + +If you have disabled all rules using the `allRules` configuration parameter, you can re-enable individual rules with their corresponding configuration parameters: + +```neon +parameters: + ergebnis: + allRules: false + privateInFinalClass: + enabled: true +``` + +## Changelog + +The maintainers of this project record notable changes to this project in a [changelog](CHANGELOG.md). + +## Contributing + +The maintainers of this project suggest following the [contribution guide](.github/CONTRIBUTING.md). + +## Code of Conduct + +The maintainers of this project ask contributors to follow the [code of conduct](https://github.com/ergebnis/.github/blob/main/CODE_OF_CONDUCT.md). + +## General Support Policy + +The maintainers of this project provide limited support. + +You can support the maintenance of this project by [sponsoring @ergebnis](https://github.com/sponsors/ergebnis). + +## PHP Version Support Policy + +This project supports PHP versions with [active and security support](https://www.php.net/supported-versions.php). + +The maintainers of this project add support for a PHP version following its initial release and drop support for a PHP version when it has reached the end of security support. + +## Security Policy + +This project has a [security policy](.github/SECURITY.md). + +## License + +This project uses the [MIT license](LICENSE.md). + +## Credits + +The method [`FinalRule::isWhitelistedClass()`](src/Classes/FinalRule.php) is inspired by the work on [`FinalClassFixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.15/src/Fixer/ClassNotation/FinalClassFixer.php) and [`FinalInternalClassFixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.15/src/Fixer/ClassNotation/FinalInternalClassFixer.php), contributed by [Dariusz Rumiński](https://github.com/keradus), [Filippo Tessarotto](https://github.com/Slamdunk), and [Spacepossum](https://github.com/SpacePossum) for [`friendsofphp/php-cs-fixer`](https://github.com/FriendsOfPHP/PHP-CS-Fixer) (originally licensed under MIT). + +## Social + +Follow [@localheinz](https://twitter.com/intent/follow?screen_name=localheinz) and [@ergebnis](https://twitter.com/intent/follow?screen_name=ergebnis) on Twitter. diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/composer.json b/tools/.phpstan/vendor/ergebnis/phpstan-rules/composer.json new file mode 100644 index 00000000000..5060dde2d30 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/composer.json @@ -0,0 +1,77 @@ +{ + "name": "ergebnis/phpstan-rules", + "description": "Provides rules for phpstan/phpstan.", + "license": "MIT", + "type": "phpstan-extension", + "keywords": [ + "phpstan", + "phpstan-rules" + ], + "authors": [ + { + "name": "Andreas Möller", + "email": "am@localheinz.com", + "homepage": "https://localheinz.com/" + } + ], + "homepage": "https://github.com/ergebnis/phpstan-rules", + "support": { + "issues": "https://github.com/ergebnis/phpstan-rules/issues", + "source": "https://github.com/ergebnis/phpstan-rules", + "security": "https://github.com/ergebnis/phpstan-rules/blob/main/.github/SECURITY.md" + }, + "require": { + "php": "~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0", + "ext-mbstring": "*", + "phpstan/phpstan": "^2.1.8" + }, + "require-dev": { + "codeception/codeception": "^4.0.0 || ^5.0.0", + "doctrine/orm": "^2.20.0 || ^3.3.0", + "ergebnis/composer-normalize": "^2.47.0", + "ergebnis/license": "^2.6.0", + "ergebnis/php-cs-fixer-config": "^6.54.0", + "ergebnis/phpunit-slow-test-detector": "^2.20.0", + "fakerphp/faker": "^1.24.1", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.7", + "phpstan/phpstan-strict-rules": "^2.0.6", + "phpunit/phpunit": "^9.6.21", + "psr/container": "^2.0.2", + "symfony/finder": "^5.4.45", + "symfony/process": "^5.4.47" + }, + "autoload": { + "psr-4": { + "Ergebnis\\PHPStan\\Rules\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "Ergebnis\\PHPStan\\Rules\\Test\\": "test/" + } + }, + "config": { + "allow-plugins": { + "ergebnis/composer-normalize": true, + "infection/extension-installer": true, + "phpstan/extension-installer": true + }, + "audit": { + "abandoned": "report" + }, + "platform": { + "php": "7.4.33" + }, + "preferred-install": "dist", + "sort-packages": true + }, + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/rules.neon b/tools/.phpstan/vendor/ergebnis/phpstan-rules/rules.neon new file mode 100644 index 00000000000..0458e5a34f1 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/rules.neon @@ -0,0 +1,292 @@ +conditionalTags: + Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule: + phpstan.rules.rule: %ergebnis.noNamedArgument.enabled% + Ergebnis\PHPStan\Rules\Classes\FinalRule: + phpstan.rules.rule: %ergebnis.final.enabled% + Ergebnis\PHPStan\Rules\Classes\NoExtendsRule: + phpstan.rules.rule: %ergebnis.noExtends.enabled% + Ergebnis\PHPStan\Rules\Classes\PHPUnit\Framework\TestCaseWithSuffixRule: + phpstan.rules.rule: %ergebnis.testCaseWithSuffix.enabled% + Ergebnis\PHPStan\Rules\Closures\NoNullableReturnTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noNullableReturnTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Closures\NoParameterPassedByReferenceRule: + phpstan.rules.rule: %ergebnis.noParameterPassedByReference.enabled% + Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noParameterWithNullableTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule: + phpstan.rules.rule: %ergebnis.noAssignByReference.enabled% + Ergebnis\PHPStan\Rules\Expressions\NoCompactRule: + phpstan.rules.rule: %ergebnis.noCompact.enabled% + Ergebnis\PHPStan\Rules\Expressions\NoErrorSuppressionRule: + phpstan.rules.rule: %ergebnis.noErrorSuppression.enabled% + Ergebnis\PHPStan\Rules\Expressions\NoEvalRule: + phpstan.rules.rule: %ergebnis.noEval.enabled% + Ergebnis\PHPStan\Rules\Expressions\NoIssetRule: + phpstan.rules.rule: %ergebnis.noIsset.enabled% + Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule: + phpstan.rules.rule: %ergebnis.declareStrictTypes.enabled% + Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noNullableReturnTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Functions\NoParameterPassedByReferenceRule: + phpstan.rules.rule: %ergebnis.noParameterPassedByReference.enabled% + Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noParameterWithNullableTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule: + phpstan.rules.rule: %ergebnis.noParameterWithNullDefaultValue.enabled% + Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule: + phpstan.rules.rule: %ergebnis.noReturnByReference.enabled% + Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule: + phpstan.rules.rule: %ergebnis.finalInAbstractClass.enabled% + Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule: + phpstan.rules.rule: %ergebnis.invokeParentHookMethod.enabled% + Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule: + phpstan.rules.rule: %ergebnis.noConstructorParameterWithDefaultValue.enabled% + Ergebnis\PHPStan\Rules\Methods\NoNullableReturnTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noNullableReturnTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Methods\NoParameterPassedByReferenceRule: + phpstan.rules.rule: %ergebnis.noParameterPassedByReference.enabled% + Ergebnis\PHPStan\Rules\Methods\NoParameterWithContainerTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noParameterWithContainerTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullableTypeDeclarationRule: + phpstan.rules.rule: %ergebnis.noParameterWithNullableTypeDeclaration.enabled% + Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullDefaultValueRule: + phpstan.rules.rule: %ergebnis.noParameterWithNullDefaultValue.enabled% + Ergebnis\PHPStan\Rules\Methods\NoReturnByReferenceRule: + phpstan.rules.rule: %ergebnis.noReturnByReference.enabled% + Ergebnis\PHPStan\Rules\Methods\PrivateInFinalClassRule: + phpstan.rules.rule: %ergebnis.privateInFinalClass.enabled% + Ergebnis\PHPStan\Rules\Statements\NoSwitchRule: + phpstan.rules.rule: %ergebnis.noSwitch.enabled% + +parameters: + ergebnis: + allRules: true + declareStrictTypes: + enabled: %ergebnis.allRules% + final: + allowAbstractClasses: true + classesNotRequiredToBeAbstractOrFinal: [] + enabled: %ergebnis.allRules% + finalInAbstractClass: + enabled: %ergebnis.allRules% + invokeParentHookMethod: + enabled: %ergebnis.allRules% + hookMethods: [] + noAssignByReference: + enabled: %ergebnis.allRules% + noCompact: + enabled: %ergebnis.allRules% + noConstructorParameterWithDefaultValue: + enabled: %ergebnis.allRules% + noErrorSuppression: + enabled: %ergebnis.allRules% + noEval: + enabled: %ergebnis.allRules% + noExtends: + classesAllowedToBeExtended: [] + enabled: %ergebnis.allRules% + noIsset: + enabled: %ergebnis.allRules% + noNamedArgument: + enabled: %ergebnis.allRules% + noNullableReturnTypeDeclaration: + enabled: %ergebnis.allRules% + noParameterPassedByReference: + enabled: %ergebnis.allRules% + noParameterWithContainerTypeDeclaration: + enabled: %ergebnis.allRules% + interfacesImplementedByContainers: + - Psr\Container\ContainerInterface + methodsAllowedToUseContainerTypeDeclarations: [] + noParameterWithNullableTypeDeclaration: + enabled: %ergebnis.allRules% + noParameterWithNullDefaultValue: + enabled: %ergebnis.allRules% + noReturnByReference: + enabled: %ergebnis.allRules% + noSwitch: + enabled: %ergebnis.allRules% + privateInFinalClass: + enabled: %ergebnis.allRules% + testCaseWithSuffix: + enabled: %ergebnis.allRules% + +parametersSchema: + ergebnis: structure([ + allRules: bool() + declareStrictTypes: structure([ + enabled: bool(), + ]) + final: structure([ + allowAbstractClasses: bool() + classesNotRequiredToBeAbstractOrFinal: listOf(string()) + enabled: bool(), + ]) + finalInAbstractClass: structure([ + enabled: bool(), + ]) + invokeParentHookMethod: structure([ + enabled: bool(), + hookMethods: listOf(structure([ + className: string(), + hasContent: anyOf("no", "yes"), + invocation: anyOf("any", "first", "last"), + methodName: string(), + ])) + ]) + noAssignByReference: structure([ + enabled: bool(), + ]) + noCompact: structure([ + enabled: bool(), + ]) + noConstructorParameterWithDefaultValue: structure([ + enabled: bool(), + ]) + noErrorSuppression: structure([ + enabled: bool(), + ]) + noExtends: structure([ + classesAllowedToBeExtended: listOf(string()) + enabled: bool(), + ]) + noEval: structure([ + enabled: bool(), + ]) + noIsset: structure([ + enabled: bool(), + ]) + noNamedArgument: structure([ + enabled: bool(), + ]) + noNullableReturnTypeDeclaration: structure([ + enabled: bool(), + ]) + noParameterPassedByReference: structure([ + enabled: bool(), + ]) + noParameterWithContainerTypeDeclaration: structure([ + enabled: bool(), + interfacesImplementedByContainers: listOf(string()) + methodsAllowedToUseContainerTypeDeclarations: listOf(string()) + ]) + noParameterWithNullableTypeDeclaration: structure([ + enabled: bool(), + ]) + noParameterWithNullDefaultValue: structure([ + enabled: bool(), + ]) + noReturnByReference: structure([ + enabled: bool(), + ]) + noSwitch: structure([ + enabled: bool(), + ]) + privateInFinalClass: structure([ + enabled: bool(), + ]) + testCaseWithSuffix: structure([ + enabled: bool(), + ]) + ]) + +services: + - + class: Ergebnis\PHPStan\Rules\Analyzer + + - + class: Ergebnis\PHPStan\Rules\CallLikes\NoNamedArgumentRule + + - + class: Ergebnis\PHPStan\Rules\Classes\FinalRule + arguments: + allowAbstractClasses: %ergebnis.final.allowAbstractClasses% + classesNotRequiredToBeAbstractOrFinal: %ergebnis.final.classesNotRequiredToBeAbstractOrFinal% + + - + class: Ergebnis\PHPStan\Rules\Classes\NoExtendsRule + arguments: + classesAllowedToBeExtended: %ergebnis.noExtends.classesAllowedToBeExtended% + + - + class: Ergebnis\PHPStan\Rules\Classes\PHPUnit\Framework\TestCaseWithSuffixRule + + - + class: Ergebnis\PHPStan\Rules\Closures\NoNullableReturnTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Closures\NoParameterPassedByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Expressions\NoCompactRule + + - + class: Ergebnis\PHPStan\Rules\Expressions\NoErrorSuppressionRule + + - + class: Ergebnis\PHPStan\Rules\Expressions\NoEvalRule + + - + class: Ergebnis\PHPStan\Rules\Expressions\NoIssetRule + + - + class: Ergebnis\PHPStan\Rules\Files\DeclareStrictTypesRule + + - + class: Ergebnis\PHPStan\Rules\Functions\NoNullableReturnTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Functions\NoParameterPassedByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullableTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Functions\NoParameterWithNullDefaultValueRule + + - + class: Ergebnis\PHPStan\Rules\Functions\NoReturnByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Methods\FinalInAbstractClassRule + + - + class: Ergebnis\PHPStan\Rules\Methods\InvokeParentHookMethodRule + arguments: + hookMethods: %ergebnis.invokeParentHookMethod.hookMethods% + + - + class: Ergebnis\PHPStan\Rules\Methods\NoConstructorParameterWithDefaultValueRule + + - + class: Ergebnis\PHPStan\Rules\Methods\NoNullableReturnTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Methods\NoParameterPassedByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Methods\NoParameterWithContainerTypeDeclarationRule + arguments: + interfacesImplementedByContainers: %ergebnis.noParameterWithContainerTypeDeclaration.interfacesImplementedByContainers% + methodsAllowedToUseContainerTypeDeclarations: %ergebnis.noParameterWithContainerTypeDeclaration.methodsAllowedToUseContainerTypeDeclarations% + + - + class: Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullableTypeDeclarationRule + + - + class: Ergebnis\PHPStan\Rules\Methods\NoParameterWithNullDefaultValueRule + + - + class: Ergebnis\PHPStan\Rules\Methods\NoReturnByReferenceRule + + - + class: Ergebnis\PHPStan\Rules\Methods\PrivateInFinalClassRule + + - + class: Ergebnis\PHPStan\Rules\Statements\NoSwitchRule diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Analyzer.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Analyzer.php new file mode 100644 index 00000000000..938cab76203 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Analyzer.php @@ -0,0 +1,68 @@ +default instanceof Node\Expr\ConstFetch) { + return false; + } + + return 'null' === $parameter->default->name->toLowerString(); + } + + /** + * @param null|Node\ComplexType|Node\Identifier|Node\Name $typeDeclaration + */ + public function isNullableTypeDeclaration($typeDeclaration): bool + { + if ($typeDeclaration instanceof Node\NullableType) { + return true; + } + + if ($typeDeclaration instanceof Node\UnionType) { + foreach ($typeDeclaration->types as $type) { + if ( + $type instanceof Node\Identifier + && 'null' === $type->toLowerString() + ) { + return true; + } + + if ( + $type instanceof Node\Name\FullyQualified + && $type->hasAttribute('originalName') + ) { + $originalName = $type->getAttribute('originalName'); + + if ( + $originalName instanceof Node\Name + && 'null' === $originalName->toLowerString() + ) { + return true; + } + } + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/CallLikes/NoNamedArgumentRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/CallLikes/NoNamedArgumentRule.php new file mode 100644 index 00000000000..a87bbaffaeb --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/CallLikes/NoNamedArgumentRule.php @@ -0,0 +1,175 @@ + + */ +final class NoNamedArgumentRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\CallLike::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->getArgs())) { + return []; + } + + /** @var list $namedArguments */ + $namedArguments = \array_values(\array_filter($node->getArgs(), static function (Node\Arg $argument): bool { + if (!$argument->name instanceof Node\Identifier) { + return false; + } + + return true; + })); + + if (0 === \count($namedArguments)) { + return []; + } + + $callLike = self::describeCallLike( + $node, + $scope, + ); + + return \array_map(static function (Node\Arg $namedArgument) use ($callLike): Rules\RuleError { + /** @var Node\Identifier $argumentName */ + $argumentName = $namedArgument->name; + + $message = \sprintf( + '%s is invoked with named argument for parameter $%s.', + $callLike, + $argumentName->toString(), + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noNamedArgument()->toString()) + ->build(); + }, $namedArguments); + } + + private static function describeCallLike( + Node\Expr\CallLike $node, + Analyser\Scope $scope + ): string { + if ($node instanceof Node\Expr\FuncCall) { + $functionName = $node->name; + + if ($functionName instanceof Node\Expr\PropertyFetch) { + return \sprintf( + 'Callable referenced by property $%s', + $functionName->name, + ); + } + + if ($functionName instanceof Node\Expr\Variable) { + return \sprintf( + 'Callable referenced by $%s', + $functionName->name, + ); + } + + if ($functionName instanceof Node\Name) { + return \sprintf( + 'Function %s()', + $functionName->name, + ); + } + } + + if ($node instanceof Node\Expr\MethodCall) { + $methodName = $node->name; + + if ($methodName instanceof Node\Identifier) { + $objectType = $scope->getType($node->var); + + $methodReflection = $scope->getMethodReflection( + $objectType, + $methodName->name, + ); + + if (null === $methodReflection) { + throw new ShouldNotHappenException(); + } + + $declaringClass = $methodReflection->getDeclaringClass(); + + if ($declaringClass->isAnonymous()) { + return \sprintf( + 'Method %s() of anonymous class', + $methodName->toString(), + ); + } + + return \sprintf( + 'Method %s::%s()', + $declaringClass->getName(), + $methodName->toString(), + ); + } + + return 'Method'; + } + + if ($node instanceof Node\Expr\StaticCall) { + $methodName = $node->name; + + if ($methodName instanceof Node\Identifier) { + $className = $node->class; + + if ($className instanceof Node\Name) { + return \sprintf( + 'Method %s::%s()', + $className->toString(), + $methodName->toString(), + ); + } + + return \sprintf( + 'Method %s()', + $methodName->toString(), + ); + } + + return 'Method'; + } + + if ($node instanceof Node\Expr\New_) { + $className = $node->class; + + if ($className instanceof Node\Name) { + return \sprintf( + 'Constructor of %s', + $className->toString(), + ); + } + + return 'Constructor'; + } + + return 'Callable'; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ClassName.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ClassName.php new file mode 100644 index 00000000000..e62b9083bf0 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ClassName.php @@ -0,0 +1,51 @@ +value = $value; + } + + /** + * @param class-string $value + */ + public static function fromString(string $value): self + { + return new self($value); + } + + /** + * @return class-string + */ + public function toString(): string + { + return $this->value; + } + + public function equals(self $other): bool + { + return $this->value === $other->value; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/FinalRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/FinalRule.php new file mode 100644 index 00000000000..05a9f3ca6d3 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/FinalRule.php @@ -0,0 +1,162 @@ + + */ +final class FinalRule implements Rules\Rule +{ + /** + * @var list + */ + private static array $whitelistedAnnotations = [ + 'Entity', + 'ORM\Entity', + 'ORM\Mapping\Entity', + ]; + + /** + * @var list + */ + private static array $whitelistedAttributes = [ + ORM\Mapping\Entity::class, + ]; + private bool $allowAbstractClasses; + + /** + * @var list + */ + private array $classesNotRequiredToBeAbstractOrFinal; + private string $errorMessageTemplate = 'Class %s is not final.'; + + /** + * @param list $classesNotRequiredToBeAbstractOrFinal + */ + public function __construct( + bool $allowAbstractClasses, + array $classesNotRequiredToBeAbstractOrFinal + ) { + $this->allowAbstractClasses = $allowAbstractClasses; + $this->classesNotRequiredToBeAbstractOrFinal = \array_map(static function (string $classNotRequiredToBeAbstractOrFinal): string { + return $classNotRequiredToBeAbstractOrFinal; + }, $classesNotRequiredToBeAbstractOrFinal); + + if ($allowAbstractClasses) { + $this->errorMessageTemplate = 'Class %s is neither abstract nor final.'; + } + } + + public function getNodeType(): string + { + return Node\Stmt\Class_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!isset($node->namespacedName)) { + return []; + } + + if (\in_array($node->namespacedName->toString(), $this->classesNotRequiredToBeAbstractOrFinal, true)) { + return []; + } + + if ( + $this->allowAbstractClasses + && $node->isAbstract() + ) { + return []; + } + + if ($node->isFinal()) { + return []; + } + + if (self::hasWhitelistedAnnotation($node)) { + return []; + } + + if (self::hasWhitelistedAttribute($node)) { + return []; + } + + $message = \sprintf( + $this->errorMessageTemplate, + $node->namespacedName->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::final()->toString()) + ->build(), + ]; + } + + /** + * This method is inspired by the work on PhpCsFixer\Fixer\ClassNotation\FinalClassFixer and + * PhpCsFixer\Fixer\ClassNotation\FinalInternalClassFixer contributed by Dariusz Rumiński, Filippo Tessarotto, and + * Spacepossum for friendsofphp/php-cs-fixer. + * + * @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.15/src/Fixer/ClassNotation/FinalClassFixer.php + * @see https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.15/src/Fixer/ClassNotation/FinalInternalClassFixer.php + * @see https://github.com/keradus + * @see https://github.com/SpacePossum + * @see https://github.com/Slamdunk + */ + private static function hasWhitelistedAnnotation(Node\Stmt\Class_ $node): bool + { + $docComment = $node->getDocComment(); + + if (!$docComment instanceof Comment\Doc) { + return false; + } + + $reformattedComment = $docComment->getReformattedText(); + + if (\is_int(\preg_match_all('/@(\S+)(?=\s|$)/', $reformattedComment, $matches))) { + foreach ($matches[1] as $annotation) { + foreach (self::$whitelistedAnnotations as $whitelistedAnnotation) { + if (0 === \mb_strpos($annotation, $whitelistedAnnotation)) { + return true; + } + } + } + } + + return false; + } + + private static function hasWhitelistedAttribute(Node\Stmt\Class_ $node): bool + { + foreach ($node->attrGroups as $attributeGroup) { + foreach ($attributeGroup->attrs as $attribute) { + if (\in_array($attribute->name->toString(), self::$whitelistedAttributes, true)) { + return true; + } + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/NoExtendsRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/NoExtendsRule.php new file mode 100644 index 00000000000..4d4864e92c3 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/NoExtendsRule.php @@ -0,0 +1,99 @@ + + */ +final class NoExtendsRule implements Rules\Rule +{ + /** + * @var list + */ + private static array $defaultClassesAllowedToBeExtended = [ + Framework\TestCase::class, + ]; + + /** + * @var list + */ + private array $classesAllowedToBeExtended; + + /** + * @param list $classesAllowedToBeExtended + */ + public function __construct(array $classesAllowedToBeExtended) + { + $this->classesAllowedToBeExtended = \array_values(\array_unique(\array_merge( + self::$defaultClassesAllowedToBeExtended, + \array_map(static function (string $classAllowedToBeExtended): string { + /** @var class-string $classAllowedToBeExtended */ + return $classAllowedToBeExtended; + }, $classesAllowedToBeExtended), + ))); + } + + public function getNodeType(): string + { + return Node\Stmt\Class_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!$node->extends instanceof Node\Name) { + return []; + } + + $extendedClassName = $node->extends->toString(); + + if (\in_array($extendedClassName, $this->classesAllowedToBeExtended, true)) { + return []; + } + + if (!isset($node->namespacedName)) { + $message = \sprintf( + 'Anonymous class is not allowed to extend "%s".', + $extendedClassName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noExtends()->toString()) + ->build(), + ]; + } + + $extendingClassName = $node->namespacedName->toString(); + + $message = \sprintf( + 'Class "%s" is not allowed to extend "%s".', + $extendingClassName, + $extendedClassName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noExtends()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/PHPUnit/Framework/TestCaseWithSuffixRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/PHPUnit/Framework/TestCaseWithSuffixRule.php new file mode 100644 index 00000000000..4b6d4792676 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Classes/PHPUnit/Framework/TestCaseWithSuffixRule.php @@ -0,0 +1,95 @@ + + */ +final class TestCaseWithSuffixRule implements Rules\Rule +{ + /** + * @var list + */ + private static array $phpunitTestCaseClassNames = [ + 'PHPUnit\Framework\TestCase', + ]; + private Reflection\ReflectionProvider $reflectionProvider; + + public function __construct(Reflection\ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + + public function getNodeType(): string + { + return Node\Stmt\Class_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if ($node->isAbstract()) { + return []; + } + + if (!$node->extends instanceof Node\Name) { + return []; + } + + if (!isset($node->namespacedName)) { + return []; + } + + $fullyQualifiedClassName = $node->namespacedName->toString(); + + $classReflection = $this->reflectionProvider->getClass($fullyQualifiedClassName); + + $extendedPhpunitTestCaseClassName = ''; + + foreach (self::$phpunitTestCaseClassNames as $phpunitTestCaseClassName) { + if ($classReflection->isSubclassOfClass($this->reflectionProvider->getClass($phpunitTestCaseClassName))) { + $extendedPhpunitTestCaseClassName = $phpunitTestCaseClassName; + + break; + } + } + + if ('' === $extendedPhpunitTestCaseClassName) { + return []; + } + + if (1 === \preg_match('/Test$/', $fullyQualifiedClassName)) { + return []; + } + + $message = \sprintf( + 'Class %s extends %s, is concrete, but does not have a Test suffix.', + $fullyQualifiedClassName, + $extendedPhpunitTestCaseClassName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::testCaseWithSuffix()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoNullableReturnTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoNullableReturnTypeDeclarationRule.php new file mode 100644 index 00000000000..64351579137 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoNullableReturnTypeDeclarationRule.php @@ -0,0 +1,53 @@ + + */ +final class NoNullableReturnTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Expr\Closure::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!$this->analyzer->isNullableTypeDeclaration($node->getReturnType())) { + return []; + } + + return [ + Rules\RuleErrorBuilder::message('Closure has a nullable return type declaration.') + ->identifier(ErrorIdentifier::noNullableReturnTypeDeclaration()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterPassedByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterPassedByReferenceRule.php new file mode 100644 index 00000000000..2c47cb742f8 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterPassedByReferenceRule.php @@ -0,0 +1,64 @@ + + */ +final class NoParameterPassedByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\Closure::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersPassedByReference = \array_values(\array_filter($node->params, static function (Node\Param $parameter): bool { + return $parameter->byRef; + })); + + if (0 === \count($parametersPassedByReference)) { + return []; + } + + return \array_map(static function (Node\Param $parameterPassedByReference): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterPassedByReference->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Closure has parameter $%s that is passed by reference.', + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterPassedByReference()->toString()) + ->build(); + }, $parametersPassedByReference); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullDefaultValueRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullDefaultValueRule.php new file mode 100644 index 00000000000..94bd1463542 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullDefaultValueRule.php @@ -0,0 +1,72 @@ + + */ +final class NoParameterWithNullDefaultValueRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Expr\Closure::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullDefaultValue = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->hasNullDefaultValue($parameter); + })); + + if (0 === \count($parametersWithNullDefaultValue)) { + return []; + } + + return \array_map(static function (Node\Param $parameterWithNullDefaultValue): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Closure has parameter $%s with null as default value.', + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullDefaultValue()->toString()) + ->build(); + }, $parametersWithNullDefaultValue); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullableTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullableTypeDeclarationRule.php new file mode 100644 index 00000000000..3cff6ee6dc5 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Closures/NoParameterWithNullableTypeDeclarationRule.php @@ -0,0 +1,72 @@ + + */ +final class NoParameterWithNullableTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Expr\Closure::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullableTypeDeclaration = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->isNullableTypeDeclaration($parameter->type); + })); + + if (0 === \count($parametersWithNullableTypeDeclaration)) { + return []; + } + + return \array_map(static function (Node\Param $parameterWithNullableTypeDeclaration): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullableTypeDeclaration->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Closure has parameter $%s with a nullable type declaration.', + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullableTypeDeclaration()->toString()) + ->build(); + }, $parametersWithNullableTypeDeclaration); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ErrorIdentifier.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ErrorIdentifier.php new file mode 100644 index 00000000000..3435c1998fa --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/ErrorIdentifier.php @@ -0,0 +1,140 @@ +value = $value; + } + + public static function declareStrictTypes(): self + { + return new self('declareStrictTypes'); + } + + public static function final(): self + { + return new self('final'); + } + + public static function finalInAbstractClass(): self + { + return new self('finalInAbstractClass'); + } + + public static function invokeParentHookMethod(): self + { + return new self('invokeParentHookMethod'); + } + + public static function noCompact(): self + { + return new self('noCompact'); + } + + public static function noConstructorParameterWithDefaultValue(): self + { + return new self('noConstructorParameterWithDefaultValue'); + } + + public static function noAssignByReference(): self + { + return new self('noAssignByReference'); + } + + public static function noErrorSuppression(): self + { + return new self('noErrorSuppression'); + } + + public static function noEval(): self + { + return new self('noEval'); + } + + public static function noExtends(): self + { + return new self('noExtends'); + } + + public static function noIsset(): self + { + return new self('noIsset'); + } + + public static function noNamedArgument(): self + { + return new self('noNamedArgument'); + } + + public static function noParameterPassedByReference(): self + { + return new self('noParameterPassedByReference'); + } + + public static function noParameterWithContainerTypeDeclaration(): self + { + return new self('noParameterWithContainerTypeDeclaration'); + } + + public static function noParameterWithNullDefaultValue(): self + { + return new self('noParameterWithNullDefaultValue'); + } + + public static function noParameterWithNullableTypeDeclaration(): self + { + return new self('noParameterWithNullableTypeDeclaration'); + } + + public static function noNullableReturnTypeDeclaration(): self + { + return new self('noNullableReturnTypeDeclaration'); + } + + public static function noReturnByReference(): self + { + return new self('noReturnByReference'); + } + + public static function noSwitch(): self + { + return new self('noSwitch'); + } + + public static function privateInFinalClass(): self + { + return new self('privateInFinalClass'); + } + + public static function testCaseWithSuffix(): self + { + return new self('testCaseWithSuffix'); + } + + public function toString(): string + { + return \sprintf( + 'ergebnis.%s', + $this->value, + ); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoAssignByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoAssignByReferenceRule.php new file mode 100644 index 00000000000..ad8cc1ef996 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoAssignByReferenceRule.php @@ -0,0 +1,41 @@ + + */ +final class NoAssignByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\AssignRef::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + return [ + Rules\RuleErrorBuilder::message('Assign by reference should not be used.') + ->identifier(ErrorIdentifier::noAssignByReference()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoCompactRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoCompactRule.php new file mode 100644 index 00000000000..cd12ffea348 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoCompactRule.php @@ -0,0 +1,49 @@ + + */ +final class NoCompactRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\FuncCall::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!$node->name instanceof Node\Name) { + return []; + } + + if ('compact' !== \mb_strtolower($scope->resolveName($node->name))) { + return []; + } + + return [ + Rules\RuleErrorBuilder::message('Function compact() should not be used.') + ->identifier(ErrorIdentifier::noCompact()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoErrorSuppressionRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoErrorSuppressionRule.php new file mode 100644 index 00000000000..49c0939c892 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoErrorSuppressionRule.php @@ -0,0 +1,41 @@ + + */ +final class NoErrorSuppressionRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\ErrorSuppress::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + return [ + Rules\RuleErrorBuilder::message('Error suppression via "@" should not be used.') + ->identifier(ErrorIdentifier::noErrorSuppression()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoEvalRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoEvalRule.php new file mode 100644 index 00000000000..b54205787fc --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoEvalRule.php @@ -0,0 +1,41 @@ + + */ +final class NoEvalRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\Eval_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + return [ + Rules\RuleErrorBuilder::message('Language construct eval() should not be used.') + ->identifier(ErrorIdentifier::noEval()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoIssetRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoIssetRule.php new file mode 100644 index 00000000000..f1443d66742 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Expressions/NoIssetRule.php @@ -0,0 +1,41 @@ + + */ +final class NoIssetRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Expr\Isset_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + return [ + Rules\RuleErrorBuilder::message('Language construct isset() should not be used.') + ->identifier(ErrorIdentifier::noIsset()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Files/DeclareStrictTypesRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Files/DeclareStrictTypesRule.php new file mode 100644 index 00000000000..5f9ec1153c9 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Files/DeclareStrictTypesRule.php @@ -0,0 +1,70 @@ + + */ +final class DeclareStrictTypesRule implements Rules\Rule +{ + public function getNodeType(): string + { + return FileNode::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + $nodes = $node->getNodes(); + + if (0 === \count($nodes)) { + return []; + } + + $firstNode = \array_shift($nodes); + + if ( + $firstNode instanceof Node\Stmt\InlineHTML + && 2 === $firstNode->getEndLine() + && 0 === \mb_strpos($firstNode->value, '#!') + ) { + $firstNode = \array_shift($nodes); + } + + if ($firstNode instanceof Node\Stmt\Declare_) { + foreach ($firstNode->declares as $declare) { + if ( + 'strict_types' === $declare->key->toLowerString() + && $declare->value instanceof Node\Scalar\LNumber + && 1 === $declare->value->value + ) { + return []; + } + } + } + + return [ + Rules\RuleErrorBuilder::message('File is missing a "declare(strict_types=1)" declaration.') + ->identifier(ErrorIdentifier::declareStrictTypes()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoNullableReturnTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoNullableReturnTypeDeclarationRule.php new file mode 100644 index 00000000000..06da4f724e8 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoNullableReturnTypeDeclarationRule.php @@ -0,0 +1,62 @@ + + */ +final class NoNullableReturnTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\Function_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!isset($node->namespacedName)) { + return []; + } + + if (!$this->analyzer->isNullableTypeDeclaration($node->getReturnType())) { + return []; + } + + $message = \sprintf( + 'Function %s() has a nullable return type declaration.', + $node->namespacedName->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noNullableReturnTypeDeclaration()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterPassedByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterPassedByReferenceRule.php new file mode 100644 index 00000000000..e461aa13900 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterPassedByReferenceRule.php @@ -0,0 +1,67 @@ + + */ +final class NoParameterPassedByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\Function_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersPassedByReference = \array_values(\array_filter($node->params, static function (Node\Param $parameter): bool { + return $parameter->byRef; + })); + + if (0 === \count($parametersPassedByReference)) { + return []; + } + + $functionName = $node->namespacedName; + + return \array_map(static function (Node\Param $parameterPassedByReference) use ($functionName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterPassedByReference->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Function %s() has parameter $%s that is passed by reference.', + $functionName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullDefaultValue()->toString()) + ->build(); + }, $parametersPassedByReference); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullDefaultValueRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullDefaultValueRule.php new file mode 100644 index 00000000000..fe82a4e3d33 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullDefaultValueRule.php @@ -0,0 +1,75 @@ + + */ +final class NoParameterWithNullDefaultValueRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\Function_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullDefaultValue = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->hasNullDefaultValue($parameter); + })); + + if (0 === \count($parametersWithNullDefaultValue)) { + return []; + } + + $functionName = $node->namespacedName; + + return \array_map(static function (Node\Param $parameterWithNullDefaultValue) use ($functionName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Function %s() has parameter $%s with null as default value.', + $functionName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullDefaultValue()->toString()) + ->build(); + }, $parametersWithNullDefaultValue); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullableTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullableTypeDeclarationRule.php new file mode 100644 index 00000000000..90275530b6f --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoParameterWithNullableTypeDeclarationRule.php @@ -0,0 +1,75 @@ + + */ +final class NoParameterWithNullableTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\Function_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullableTypeDeclaration = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->isNullableTypeDeclaration($parameter->type); + })); + + if (0 === \count($parametersWithNullableTypeDeclaration)) { + return []; + } + + $functionName = $node->namespacedName; + + return \array_map(static function (Node\Param $parameterWithNullableTypeDeclaration) use ($functionName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullableTypeDeclaration->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Function %s() has parameter $%s with a nullable type declaration.', + $functionName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullableTypeDeclaration()->toString()) + ->build(); + }, $parametersWithNullableTypeDeclaration); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoReturnByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoReturnByReferenceRule.php new file mode 100644 index 00000000000..0efb7008b71 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Functions/NoReturnByReferenceRule.php @@ -0,0 +1,50 @@ + + */ +final class NoReturnByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\Function_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (false === $node->byRef) { + return []; + } + + $message = \sprintf( + 'Function %s() returns by reference.', + $node->namespacedName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noReturnByReference()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HasContent.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HasContent.php new file mode 100644 index 00000000000..ced81778b9a --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HasContent.php @@ -0,0 +1,74 @@ +value = $value; + } + + /** + * @throws \InvalidArgumentException + */ + public static function fromString(string $value): self + { + $values = [ + 'maybe', + 'no', + 'yes', + ]; + + if (!\in_array($value, $values, true)) { + throw new \InvalidArgumentException(\sprintf( + 'Value needs to be one of "%s", got "%s" instead.', + \implode('", "', $values), + $value, + )); + } + + return new self($value); + } + + public static function maybe(): self + { + return new self('maybe'); + } + + public static function no(): self + { + return new self('no'); + } + + public static function yes(): self + { + return new self('yes'); + } + + public function toString(): string + { + return $this->value; + } + + public function equals(self $other): bool + { + return $this->value === $other->value; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HookMethod.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HookMethod.php new file mode 100644 index 00000000000..2d14cad7b5d --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/HookMethod.php @@ -0,0 +1,71 @@ +className = $className; + $this->methodName = $methodName; + $this->invocation = $invocation; + $this->hasContent = $hasContent; + } + + public static function create( + ClassName $className, + MethodName $methodName, + Invocation $invocation, + HasContent $hasContent + ): self { + return new self( + $className, + $methodName, + $invocation, + $hasContent, + ); + } + + public function className(): ClassName + { + return $this->className; + } + + public function methodName(): MethodName + { + return $this->methodName; + } + + public function invocation(): Invocation + { + return $this->invocation; + } + + public function hasContent(): HasContent + { + return $this->hasContent; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Invocation.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Invocation.php new file mode 100644 index 00000000000..722ff5f1ac3 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Invocation.php @@ -0,0 +1,86 @@ +value = $value; + } + + /** + * @throws \InvalidArgumentException + */ + public static function fromString(string $value): self + { + $values = [ + 'any', + 'first', + 'last', + 'never', + ]; + + if (!\in_array($value, $values, true)) { + throw new \InvalidArgumentException(\sprintf( + 'Value needs to be one of "%s", got "%s" instead.', + \implode('", "', $values), + $value, + )); + } + + return new self($value); + } + + public static function any(): self + { + return new self('any'); + } + + public static function first(): self + { + return new self('first'); + } + + public static function last(): self + { + return new self('last'); + } + + public static function never(): self + { + return new self('never'); + } + + /** + * @return non-empty-string + */ + public function toString(): string + { + return $this->value; + } + + public function equals(self $other): bool + { + return $this->value === $other->value; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/MethodName.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/MethodName.php new file mode 100644 index 00000000000..47116cefb46 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/MethodName.php @@ -0,0 +1,51 @@ +value = $value; + } + + /** + * @param non-empty-string $value + */ + public static function fromString(string $value): self + { + return new self($value); + } + + /** + * @return non-empty-string + */ + public function toString(): string + { + return $this->value; + } + + public function equals(self $other): bool + { + return $this->value === $other->value; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/FinalInAbstractClassRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/FinalInAbstractClassRule.php new file mode 100644 index 00000000000..271870aee8e --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/FinalInAbstractClassRule.php @@ -0,0 +1,124 @@ + + */ +final class FinalInAbstractClassRule implements Rules\Rule +{ + private const DOCTRINE_ATTRIBUTE_NAMES = [ + ORM\Mapping\Embeddable::class, + ORM\Mapping\Entity::class, + ]; + private const DOCTRINE_ANNOTATION_NAMES = [ + '@ORM\\Mapping\\Embeddable', + '@ORM\\Embeddable', + '@Embeddable', + '@ORM\\Mapping\\Entity', + '@ORM\\Entity', + '@Entity', + ]; + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + /** @var Reflection\ClassReflection $containingClass */ + $containingClass = $scope->getClassReflection(); + + if (self::isDoctrineEntity($containingClass)) { + return []; + } + + if (!$containingClass->isAbstract()) { + return []; + } + + if ($containingClass->isInterface()) { + return []; + } + + if ($node->isAbstract()) { + return []; + } + + if ($node->isFinal()) { + return []; + } + + if ($node->isPrivate()) { + return []; + } + + if ('__construct' === $node->name->name) { + return []; + } + + $message = \sprintf( + 'Method %s::%s() is not final, but since the containing class is abstract, it should be.', + $containingClass->getName(), + $node->name->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::finalInAbstractClass()->toString()) + ->build(), + ]; + } + + private static function isDoctrineEntity(Reflection\ClassReflection $containingClass): bool + { + $attributes = $containingClass->getNativeReflection()->getAttributes(); + + foreach ($attributes as $attribute) { + if (\in_array($attribute->getName(), self::DOCTRINE_ATTRIBUTE_NAMES, true)) { + return true; + } + } + + $resolvedPhpDocBlock = $containingClass->getResolvedPhpDoc(); + + if ($resolvedPhpDocBlock instanceof PhpDoc\ResolvedPhpDocBlock) { + foreach ($resolvedPhpDocBlock->getPhpDocNodes() as $phpDocNode) { + foreach ($phpDocNode->children as $child) { + if (!$child instanceof PhpDocParser\Ast\PhpDoc\PhpDocTagNode) { + continue; + } + + if (\in_array($child->name, self::DOCTRINE_ANNOTATION_NAMES, true)) { + return true; + } + } + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/InvokeParentHookMethodRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/InvokeParentHookMethodRule.php new file mode 100644 index 00000000000..888aa922e41 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/InvokeParentHookMethodRule.php @@ -0,0 +1,436 @@ + + */ +final class InvokeParentHookMethodRule implements Rules\Rule +{ + private Reflection\ReflectionProvider $reflectionProvider; + + /** + * @var list + */ + private array $hookMethods; + + /** + * @param array> $hookMethods + */ + public function __construct( + Reflection\ReflectionProvider $reflectionProvider, + array $hookMethods = [] + ) { + $this->reflectionProvider = $reflectionProvider; + $this->hookMethods = self::sort( + $reflectionProvider, + ...self::filter( + $reflectionProvider, + ...\array_merge( + self::defaultHookMethods(), + \array_map(static function (array $hookMethod): HookMethod { + return HookMethod::create( + ClassName::fromString($hookMethod['className']), + MethodName::fromString($hookMethod['methodName']), + Invocation::fromString($hookMethod['invocation']), + HasContent::fromString($hookMethod['hasContent']), + ); + }, $hookMethods), + ), + ), + ); + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + $classReflection = $scope->getClassReflection(); + + if (null === $classReflection) { + return []; + } + + $parentClassReflection = $classReflection->getParentClass(); + + if (null === $parentClassReflection) { + return []; + } + + $methodName = $node->name->toString(); + + $hookMethod = $this->findMatchingHookMethod( + $scope, + $parentClassReflection, + $classReflection, + $methodName, + ); + + if (!$hookMethod instanceof HookMethod) { + return []; + } + + $statements = $node->getStmts(); + + if (!\is_array($statements)) { + throw new ShouldNotHappenException(); + } + + $parentHookMethodInvocation = self::findParentHookMethodInvocation( + \array_values($statements), + $hookMethod, + ); + + if ($parentHookMethodInvocation->equals(Invocation::never())) { + if ($hookMethod->hasContent()->equals(HasContent::no())) { + return []; + } + + $message = \sprintf( + 'Method %s::%s() does not invoke parent::%s().', + $classReflection->getName(), + $methodName, + $hookMethod->methodName()->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::invokeParentHookMethod()->toString()) + ->build(), + ]; + } + + if ($parentHookMethodInvocation->equals($hookMethod->invocation())) { + return []; + } + + if ($hookMethod->invocation()->equals(Invocation::first())) { + $message = \sprintf( + 'Method %s::%s() does not invoke parent::%s() before all other statements.', + $classReflection->getName(), + $methodName, + $hookMethod->methodName()->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::invokeParentHookMethod()->toString()) + ->build(), + ]; + } + + if ($hookMethod->invocation()->equals(Invocation::last())) { + $message = \sprintf( + 'Method %s::%s() does not invoke parent::%s() after all other statements.', + $classReflection->getName(), + $methodName, + $hookMethod->methodName()->toString(), + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::invokeParentHookMethod()->toString()) + ->build(), + ]; + } + + throw new ShouldNotHappenException(); + } + + private function findMatchingHookMethod( + Analyser\Scope $scope, + Reflection\ClassReflection $parentClassReflection, + Reflection\ClassReflection $classReflection, + string $methodName + ): ?HookMethod { + foreach ($this->hookMethods as $hookMethod) { + if (!$classReflection->isSubclassOfClass($this->reflectionProvider->getClass($hookMethod->className()->toString()))) { + continue; + } + + if (\mb_strtolower($hookMethod->methodName()->toString()) !== \mb_strtolower($methodName)) { + continue; + } + + $parentMethodReflection = $parentClassReflection->getMethod( + $methodName, + $scope, + ); + + $declaringClassReflection = $parentMethodReflection->getDeclaringClass(); + + if (\mb_strtolower($hookMethod->className()->toString()) !== \mb_strtolower($declaringClassReflection->getName())) { + return HookMethod::create( + ClassName::fromString($declaringClassReflection->getName()), + MethodName::fromString($methodName), + $hookMethod->invocation(), + HasContent::maybe(), + ); + } + + return $hookMethod; + } + + return null; + } + + /** + * @param list $statements + */ + private static function findParentHookMethodInvocation( + array $statements, + HookMethod $hookMethod + ): Invocation { + $statementsWithOperations = \array_filter($statements, static function (Node $statement): bool { + if ($statement instanceof Node\Stmt\Nop) { + return false; + } + + return true; + }); + + $statementCount = \count($statementsWithOperations); + + foreach ($statementsWithOperations as $index => $statement) { + if (!$statement instanceof Node\Stmt\Expression) { + continue; + } + + if (!$statement->expr instanceof Node\Expr\StaticCall) { + continue; + } + + if (!$statement->expr->class instanceof Node\Name) { + continue; + } + + $className = (string) $statement->expr->class; + + if (\mb_strtolower($className) !== 'parent') { + continue; + } + + if (!$statement->expr->name instanceof Node\Identifier) { + continue; + } + + if (\mb_strtolower($statement->expr->name->toString()) === \mb_strtolower($hookMethod->methodName()->toString())) { + if (1 === $statementCount) { + return $hookMethod->invocation(); + } + + if (0 === $index) { + return Invocation::first(); + } + + if ($statementCount - 1 === $index) { + return Invocation::last(); + } + + return Invocation::any(); + } + } + + return Invocation::never(); + } + + /** + * @return list + */ + private static function filter( + Reflection\ReflectionProvider $reflectionProvider, + HookMethod ...$hookMethods + ): array { + return \array_values(\array_filter($hookMethods, static function (HookMethod $hookMethod) use ($reflectionProvider): bool { + return $reflectionProvider->hasClass($hookMethod->className()->toString()); + })); + } + + /** + * @return list + */ + private static function sort( + Reflection\ReflectionProvider $reflectionProvider, + HookMethod ...$hookMethods + ): array { + \usort($hookMethods, static function (HookMethod $a, HookMethod $b) use ($reflectionProvider): int { + if (\mb_strtolower($a->className()->toString()) === \mb_strtolower($b->className()->toString())) { + return 0; + } + + if ($reflectionProvider->getClass($a->className()->toString())->isSubclassOfClass($reflectionProvider->getClass($b->className()->toString()))) { + return -1; + } + + return 1; + }); + + return $hookMethods; + } + + /** + * @return list + */ + private static function defaultHookMethods(): array + { + return [ + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2083-L2085 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('assertPostConditions'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2073-L2075 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('assertPreConditions'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2063-L2065 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('setUp'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2055-L2057 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('setUpBeforeClass'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2091-L2093 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('tearDown'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/sebastianbergmann/phpunit/blob/6.0.0/src/Framework/TestCase.php#L2098-L2100 + */ + HookMethod::create( + ClassName::fromString(Framework\TestCase::class), + MethodName::fromString('tearDownAfterClass'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L11-L13 + */ + HookMethod::create( + ClassName::fromString(PHPUnit\TestCase::class), + MethodName::fromString('_setUp'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L25-L27 + */ + HookMethod::create( + ClassName::fromString(PHPUnit\TestCase::class), + MethodName::fromString('_setUpBeforeClass'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L18-L20 + */ + HookMethod::create( + ClassName::fromString(PHPUnit\TestCase::class), + MethodName::fromString('_tearDown'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/phpunit-wrapper/blob/9.0.0/src/TestCase.php#L32-L34 + */ + HookMethod::create( + ClassName::fromString(PHPUnit\TestCase::class), + MethodName::fromString('_tearDownAfterClass'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L75-L77 + */ + HookMethod::create( + ClassName::fromString(Test\Unit::class), + MethodName::fromString('_after'), + Invocation::last(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L63-L65 + */ + HookMethod::create( + ClassName::fromString(Test\Unit::class), + MethodName::fromString('_before'), + Invocation::first(), + HasContent::no(), + ), + /** + * @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L34-L58 + */ + HookMethod::create( + ClassName::fromString(Test\Unit::class), + MethodName::fromString('_setUp'), + Invocation::first(), + HasContent::yes(), + ), + /** + * @see https://github.com/Codeception/Codeception/blob/4.2.2/src/Codeception/Test/Unit.php#L67-L70 + */ + HookMethod::create( + ClassName::fromString(Test\Unit::class), + MethodName::fromString('_tearDown'), + Invocation::last(), + HasContent::yes(), + ), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoConstructorParameterWithDefaultValueRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoConstructorParameterWithDefaultValueRule.php new file mode 100644 index 00000000000..e8b7e34a3f7 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoConstructorParameterWithDefaultValueRule.php @@ -0,0 +1,99 @@ + + */ +final class NoConstructorParameterWithDefaultValueRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if ('__construct' !== $node->name->toLowerString()) { + return []; + } + + if (0 === \count($node->params)) { + return []; + } + + $parametersWithDefaultValue = \array_values(\array_filter($node->params, static function (Node\Param $parameter): bool { + return self::hasDefaultValue($parameter); + })); + + if (0 === \count($parametersWithDefaultValue)) { + return []; + } + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + return \array_map(static function (Node\Param $parameterWithDefaultValue): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Constructor in anonymous class has parameter $%s with default value.', + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noConstructorParameterWithDefaultValue()->toString()) + ->build(); + }, $parametersWithDefaultValue); + } + + $className = $classReflection->getName(); + + return \array_map(static function (Node\Param $parameterWithDefaultValue) use ($className): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Constructor in %s has parameter $%s with default value.', + $className, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noConstructorParameterWithDefaultValue()->toString()) + ->build(); + }, $parametersWithDefaultValue); + } + + private static function hasDefaultValue(Node\Param $parameter): bool + { + return null !== $parameter->default; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoNullableReturnTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoNullableReturnTypeDeclarationRule.php new file mode 100644 index 00000000000..e0e84c94719 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoNullableReturnTypeDeclarationRule.php @@ -0,0 +1,76 @@ + + */ +final class NoNullableReturnTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (!$this->analyzer->isNullableTypeDeclaration($node->getReturnType())) { + return []; + } + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + $message = \sprintf( + 'Method %s() in anonymous class has a nullable return type declaration.', + $node->name->name, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noNullableReturnTypeDeclaration()->toString()) + ->build(), + ]; + } + + $message = \sprintf( + 'Method %s::%s() has a nullable return type declaration.', + $classReflection->getName(), + $node->name->name, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noNullableReturnTypeDeclaration()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterPassedByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterPassedByReferenceRule.php new file mode 100644 index 00000000000..4c90f696de0 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterPassedByReferenceRule.php @@ -0,0 +1,94 @@ + + */ +final class NoParameterPassedByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersExplicitlyPassedByReference = \array_values(\array_filter($node->params, static function (Node\Param $parameter): bool { + return $parameter->byRef; + })); + + if (0 === \count($parametersExplicitlyPassedByReference)) { + return []; + } + + $methodName = $node->name->toString(); + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + return \array_map(static function (Node\Param $parameterExplicitlyPassedByReference) use ($methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterExplicitlyPassedByReference->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s() in anonymous class has parameter $%s that is passed by reference.', + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterPassedByReference()->toString()) + ->build(); + }, $parametersExplicitlyPassedByReference); + } + + $className = $classReflection->getName(); + + return \array_map(static function (Node\Param $parameterExplicitlyPassedByReference) use ($className, $methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterExplicitlyPassedByReference->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s::%s() has parameter $%s that is passed by reference.', + $className, + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterPassedByReference()->toString()) + ->build(); + }, $parametersExplicitlyPassedByReference); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithContainerTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithContainerTypeDeclarationRule.php new file mode 100644 index 00000000000..f64a8312c39 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithContainerTypeDeclarationRule.php @@ -0,0 +1,179 @@ + + */ +final class NoParameterWithContainerTypeDeclarationRule implements Rules\Rule +{ + private Reflection\ReflectionProvider $reflectionProvider; + + /** + * @var list + */ + private array $interfacesImplementedByContainers; + + /** + * @var list + */ + private array $methodsAllowedToUseContainerTypeDeclarations; + + /** + * @param list $interfacesImplementedByContainers + * @param list $methodsAllowedToUseContainerTypeDeclarations + */ + public function __construct( + Reflection\ReflectionProvider $reflectionProvider, + array $interfacesImplementedByContainers, + array $methodsAllowedToUseContainerTypeDeclarations + ) { + $this->reflectionProvider = $reflectionProvider; + $this->interfacesImplementedByContainers = \array_values(\array_filter( + \array_map(static function (string $interfaceImplementedByContainers): string { + return $interfaceImplementedByContainers; + }, $interfacesImplementedByContainers), + static function (string $interfaceImplementedByContainer): bool { + return \interface_exists($interfaceImplementedByContainer); + }, + )); + $this->methodsAllowedToUseContainerTypeDeclarations = $methodsAllowedToUseContainerTypeDeclarations; + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($this->interfacesImplementedByContainers)) { + return []; + } + + if (0 === \count($node->params)) { + return []; + } + + $methodName = $node->name->toString(); + + if (\in_array($methodName, $this->methodsAllowedToUseContainerTypeDeclarations, true)) { + return []; + } + + /** @var Reflection\ClassReflection $containingClass */ + $containingClass = $scope->getClassReflection(); + + return \array_values(\array_reduce( + $node->params, + function (array $errors, Node\Param $node) use ($scope, $containingClass, $methodName): array { + $type = $node->type; + + if (!$type instanceof Node\Name) { + return $errors; + } + + /** @var Node\Expr\Variable $variable */ + $variable = $node->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $classUsedInTypeDeclaration = $this->reflectionProvider->getClass($scope->resolveName($type)); + + if ($classUsedInTypeDeclaration->isInterface()) { + foreach ($this->interfacesImplementedByContainers as $interfaceImplementedByContainer) { + if ($classUsedInTypeDeclaration->getName() === $interfaceImplementedByContainer) { + $errors[] = self::createError( + $containingClass, + $methodName, + $parameterName, + $classUsedInTypeDeclaration, + ); + + return $errors; + } + + if ($classUsedInTypeDeclaration->getNativeReflection()->isSubclassOf($interfaceImplementedByContainer)) { + $errors[] = self::createError( + $containingClass, + $methodName, + $parameterName, + $classUsedInTypeDeclaration, + ); + + return $errors; + } + } + } + + foreach ($this->interfacesImplementedByContainers as $interfaceImplementedByContainer) { + if ($classUsedInTypeDeclaration->getNativeReflection()->implementsInterface($interfaceImplementedByContainer)) { + $errors[] = self::createError( + $containingClass, + $methodName, + $parameterName, + $classUsedInTypeDeclaration, + ); + + return $errors; + } + } + + return $errors; + }, + [], + )); + } + + private static function createError( + Reflection\ClassReflection $classReflection, + string $methodName, + string $parameterName, + Reflection\ClassReflection $classUsedInTypeDeclaration + ): Rules\RuleError { + if ($classReflection->isAnonymous()) { + $message = \sprintf( + 'Method %s() in anonymous class has a parameter $%s with a type declaration of %s, but containers should not be injected.', + $methodName, + $parameterName, + $classUsedInTypeDeclaration->getName(), + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithContainerTypeDeclaration()->toString()) + ->build(); + } + + $message = \sprintf( + 'Method %s::%s() has a parameter $%s with a type declaration of %s, but containers should not be injected.', + $classReflection->getName(), + $methodName, + $parameterName, + $classUsedInTypeDeclaration->getName(), + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithContainerTypeDeclaration()->toString()) + ->build(); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullDefaultValueRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullDefaultValueRule.php new file mode 100644 index 00000000000..9888974c695 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullDefaultValueRule.php @@ -0,0 +1,102 @@ + + */ +final class NoParameterWithNullDefaultValueRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullDefaultValue = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->hasNullDefaultValue($parameter); + })); + + if (0 === \count($parametersWithNullDefaultValue)) { + return []; + } + + $methodName = $node->name->toString(); + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + return \array_map(static function (Node\Param $parameterWithNullDefaultValue) use ($methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s() in anonymous class has parameter $%s with null as default value.', + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullDefaultValue()->toString()) + ->build(); + }, $parametersWithNullDefaultValue); + } + + $className = $classReflection->getName(); + + return \array_map(static function (Node\Param $parameterWithNullDefaultValue) use ($className, $methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullDefaultValue->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s::%s() has parameter $%s with null as default value.', + $className, + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullDefaultValue()->toString()) + ->build(); + }, $parametersWithNullDefaultValue); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullableTypeDeclarationRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullableTypeDeclarationRule.php new file mode 100644 index 00000000000..632cd7bea27 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoParameterWithNullableTypeDeclarationRule.php @@ -0,0 +1,102 @@ + + */ +final class NoParameterWithNullableTypeDeclarationRule implements Rules\Rule +{ + private Analyzer $analyzer; + + public function __construct(Analyzer $analyzer) + { + $this->analyzer = $analyzer; + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (0 === \count($node->params)) { + return []; + } + + $parametersWithNullableTypeDeclaration = \array_values(\array_filter($node->params, function (Node\Param $parameter): bool { + return $this->analyzer->isNullableTypeDeclaration($parameter->type); + })); + + if (0 === \count($parametersWithNullableTypeDeclaration)) { + return []; + } + + $methodName = $node->name->toString(); + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + return \array_map(static function (Node\Param $parameterWithNullableTypeDeclaration) use ($methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullableTypeDeclaration->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s() in anonymous class has parameter $%s with a nullable type declaration.', + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullableTypeDeclaration()->toString()) + ->build(); + }, $parametersWithNullableTypeDeclaration); + } + + $className = $classReflection->getName(); + + return \array_map(static function (Node\Param $parameterWithNullableTypeDeclaration) use ($className, $methodName): Rules\RuleError { + /** @var Node\Expr\Variable $variable */ + $variable = $parameterWithNullableTypeDeclaration->var; + + /** @var string $parameterName */ + $parameterName = $variable->name; + + $message = \sprintf( + 'Method %s::%s() has parameter $%s with a nullable type declaration.', + $className, + $methodName, + $parameterName, + ); + + return Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noParameterWithNullableTypeDeclaration()->toString()) + ->build(); + }, $parametersWithNullableTypeDeclaration); + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoReturnByReferenceRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoReturnByReferenceRule.php new file mode 100644 index 00000000000..a1bf87ff604 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/NoReturnByReferenceRule.php @@ -0,0 +1,72 @@ + + */ +final class NoReturnByReferenceRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + if (false === $node->byRef) { + return []; + } + + $methodName = $node->name->toString(); + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + $message = \sprintf( + 'Method %s() in anonymous class returns by reference.', + $methodName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noReturnByReference()->toString()) + ->build(), + ]; + } + + $className = $classReflection->getName(); + + $message = \sprintf( + 'Method %s::%s() returns by reference.', + $className, + $methodName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::noReturnByReference()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/PrivateInFinalClassRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/PrivateInFinalClassRule.php new file mode 100644 index 00000000000..9aa2c3cc286 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Methods/PrivateInFinalClassRule.php @@ -0,0 +1,198 @@ + + */ +final class PrivateInFinalClassRule implements Rules\Rule +{ + /** + * @var list + */ + private static array $whitelistedAnnotations = [ + '@after', + '@before', + '@postCondition', + '@preCondition', + ]; + + /** + * @var list + */ + private static array $whitelistedAttributes = [ + Framework\Attributes\After::class, + Framework\Attributes\Before::class, + Framework\Attributes\PostCondition::class, + Framework\Attributes\PreCondition::class, + ]; + private Type\FileTypeMapper $fileTypeMapper; + + public function __construct(Type\FileTypeMapper $fileTypeMapper) + { + $this->fileTypeMapper = $fileTypeMapper; + } + + public function getNodeType(): string + { + return Node\Stmt\ClassMethod::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + /** @var Reflection\ClassReflection $containingClass */ + $containingClass = $scope->getClassReflection(); + + if (!$containingClass->isFinal()) { + return []; + } + + if ($node->isPublic()) { + return []; + } + + if ($node->isPrivate()) { + return []; + } + + if ($this->hasWhitelistedAnnotation($node, $containingClass)) { + return []; + } + + if (self::hasWhitelistedAttribute($node)) { + return []; + } + + $methodName = $node->name->toString(); + + if (self::isDeclaredByParentClass($containingClass, $methodName)) { + return []; + } + + if (self::isDeclaredByTrait($containingClass, $methodName)) { + return []; + } + + /** @var Reflection\ClassReflection $classReflection */ + $classReflection = $scope->getClassReflection(); + + if ($classReflection->isAnonymous()) { + $message = \sprintf( + 'Method %s() in anonymous class is protected, but since the containing class is final, it can be private.', + $node->name->name, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::privateInFinalClass()->toString()) + ->build(), + ]; + } + + $message = \sprintf( + 'Method %s::%s() is protected, but since the containing class is final, it can be private.', + $containingClass->getName(), + $methodName, + ); + + return [ + Rules\RuleErrorBuilder::message($message) + ->identifier(ErrorIdentifier::privateInFinalClass()->toString()) + ->build(), + ]; + } + + private function hasWhitelistedAnnotation( + Node\Stmt\ClassMethod $node, + Reflection\ClassReflection $containingClass + ): bool { + $docComment = $node->getDocComment(); + + if (!$docComment instanceof Comment\Doc) { + return false; + } + + $resolvedPhpDoc = $this->fileTypeMapper->getResolvedPhpDoc( + null, + $containingClass->getName(), + null, + null, + $docComment->getText(), + ); + + foreach ($resolvedPhpDoc->getPhpDocNodes() as $phpDocNode) { + foreach ($phpDocNode->getTags() as $tag) { + if (\in_array($tag->name, self::$whitelistedAnnotations, true)) { + return true; + } + } + } + + return false; + } + + private static function hasWhitelistedAttribute(Node\Stmt\ClassMethod $node): bool + { + foreach ($node->attrGroups as $attributeGroup) { + foreach ($attributeGroup->attrs as $attribute) { + if (\in_array($attribute->name->toString(), self::$whitelistedAttributes, true)) { + return true; + } + } + } + + return false; + } + + private static function isDeclaredByParentClass( + Reflection\ClassReflection $containingClass, + string $methodName + ): bool { + $parentClass = $containingClass->getNativeReflection()->getParentClass(); + + if (!$parentClass instanceof \ReflectionClass) { + return false; + } + + if (!$parentClass->hasMethod($methodName)) { + return false; + } + + return true; + } + + private static function isDeclaredByTrait( + Reflection\ClassReflection $containingClass, + string $methodName + ): bool { + foreach ($containingClass->getTraits() as $trait) { + if ($trait->hasMethod($methodName)) { + return true; + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Statements/NoSwitchRule.php b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Statements/NoSwitchRule.php new file mode 100644 index 00000000000..127e5eed3e0 --- /dev/null +++ b/tools/.phpstan/vendor/ergebnis/phpstan-rules/src/Statements/NoSwitchRule.php @@ -0,0 +1,41 @@ + + */ +final class NoSwitchRule implements Rules\Rule +{ + public function getNodeType(): string + { + return Node\Stmt\Switch_::class; + } + + public function processNode( + Node $node, + Analyser\Scope $scope + ): array { + return [ + Rules\RuleErrorBuilder::message('Control structures using switch should not be used.') + ->identifier(ErrorIdentifier::noSwitch()->toString()) + ->build(), + ]; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/.phpstorm.meta.php b/tools/.phpstan/vendor/nette/utils/.phpstorm.meta.php new file mode 100644 index 00000000000..25851af66c0 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/.phpstorm.meta.php @@ -0,0 +1,13 @@ + +✅ [Callback](https://doc.nette.org/utils/callback) - PHP callbacks
    +✅ [Filesystem](https://doc.nette.org/utils/filesystem) - copying, renaming, …
    +✅ [Finder](https://doc.nette.org/utils/finder) - finds files and directories
    +✅ [Floats](https://doc.nette.org/utils/floats) - floating point numbers
    +✅ [Helper Functions](https://doc.nette.org/utils/helpers)
    +✅ [HTML elements](https://doc.nette.org/utils/html-elements) - generate HTML
    +✅ [Images](https://doc.nette.org/utils/images) - crop, resize, rotate images
    +✅ [Iterables](https://doc.nette.org/utils/iterables)
    +✅ [JSON](https://doc.nette.org/utils/json) - encoding and decoding
    +✅ [Generating Random Strings](https://doc.nette.org/utils/random)
    +✅ [Paginator](https://doc.nette.org/utils/paginator) - pagination math
    +✅ [PHP Reflection](https://doc.nette.org/utils/reflection)
    +✅ [Strings](https://doc.nette.org/utils/strings) - useful text functions
    +✅ [SmartObject](https://doc.nette.org/utils/smartobject) - PHP object enhancements
    +✅ [Type](https://doc.nette.org/utils/type) - PHP data type
    +✅ [Validation](https://doc.nette.org/utils/validators) - validate inputs
    + +  + +Installation +------------ + +The recommended way to install is via Composer: + +``` +composer require nette/utils +``` + +Nette Utils 4.1 is compatible with PHP 8.2 to 8.5. + +  + +[Support Me](https://github.com/sponsors/dg) +-------------------------------------------- + +Do you like Nette Utils? Are you looking forward to the new features? + +[![Buy me a coffee](https://files.nette.org/icons/donation-3.svg)](https://github.com/sponsors/dg) + +Thank you! diff --git a/tools/.phpstan/vendor/nette/utils/src/HtmlStringable.php b/tools/.phpstan/vendor/nette/utils/src/HtmlStringable.php new file mode 100644 index 00000000000..d749d4ee8cd --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/HtmlStringable.php @@ -0,0 +1,22 @@ +counter === 1 || ($gridWidth && $this->counter !== 0 && (($this->counter - 1) % $gridWidth) === 0); + } + + + /** + * Is the current element the last one? + */ + public function isLast(?int $gridWidth = null): bool + { + return !$this->hasNext() || ($gridWidth && ($this->counter % $gridWidth) === 0); + } + + + /** + * Is the iterator empty? + */ + public function isEmpty(): bool + { + return $this->counter === 0; + } + + + /** + * Is the counter odd? + */ + public function isOdd(): bool + { + return $this->counter % 2 === 1; + } + + + /** + * Is the counter even? + */ + public function isEven(): bool + { + return $this->counter % 2 === 0; + } + + + /** + * Returns the counter. + */ + public function getCounter(): int + { + return $this->counter; + } + + + /** + * Returns the count of elements. + */ + public function count(): int + { + $inner = $this->getInnerIterator(); + if ($inner instanceof \Countable) { + return $inner->count(); + + } else { + throw new Nette\NotSupportedException('Iterator is not countable.'); + } + } + + + /** + * Forwards to the next element. + */ + public function next(): void + { + parent::next(); + if (parent::valid()) { + $this->counter++; + } + } + + + /** + * Rewinds the Iterator. + */ + public function rewind(): void + { + parent::rewind(); + $this->counter = parent::valid() ? 1 : 0; + } + + + /** + * Returns the next key. + */ + public function getNextKey(): mixed + { + return $this->getInnerIterator()->key(); + } + + + /** + * Returns the next element. + */ + public function getNextValue(): mixed + { + return $this->getInnerIterator()->current(); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Iterators/Mapper.php b/tools/.phpstan/vendor/nette/utils/src/Iterators/Mapper.php new file mode 100644 index 00000000000..284da29da4c --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Iterators/Mapper.php @@ -0,0 +1,33 @@ +callback = $callback; + } + + + public function current(): mixed + { + return ($this->callback)(parent::current(), parent::key()); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/SmartObject.php b/tools/.phpstan/vendor/nette/utils/src/SmartObject.php new file mode 100644 index 00000000000..3b2203f1f74 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/SmartObject.php @@ -0,0 +1,140 @@ +$name ?? null; + if (is_iterable($handlers)) { + foreach ($handlers as $handler) { + $handler(...$args); + } + } elseif ($handlers !== null) { + throw new UnexpectedValueException("Property $class::$$name must be iterable or null, " . get_debug_type($handlers) . ' given.'); + } + + return null; + } + + ObjectHelpers::strictCall($class, $name); + } + + + /** + * @throws MemberAccessException + */ + public static function __callStatic(string $name, array $args) + { + ObjectHelpers::strictStaticCall(static::class, $name); + } + + + /** + * @return mixed + * @throws MemberAccessException if the property is not defined. + */ + public function &__get(string $name) + { + $class = static::class; + + if ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) { // property getter + if (!($prop & 0b0001)) { + throw new MemberAccessException("Cannot read a write-only property $class::\$$name."); + } + + $m = ($prop & 0b0010 ? 'get' : 'is') . ucfirst($name); + if ($prop & 0b10000) { + $trace = debug_backtrace(0, 1)[0]; // suppose this method is called from __call() + $loc = isset($trace['file'], $trace['line']) + ? " in $trace[file] on line $trace[line]" + : ''; + trigger_error("Property $class::\$$name is deprecated, use $class::$m() method$loc.", E_USER_DEPRECATED); + } + + if ($prop & 0b0100) { // return by reference + return $this->$m(); + } else { + $val = $this->$m(); + return $val; + } + } else { + ObjectHelpers::strictGet($class, $name); + } + } + + + /** + * @throws MemberAccessException if the property is not defined or is read-only + */ + public function __set(string $name, mixed $value): void + { + $class = static::class; + + if (ObjectHelpers::hasProperty($class, $name)) { // unsetted property + $this->$name = $value; + + } elseif ($prop = ObjectHelpers::getMagicProperties($class)[$name] ?? null) { // property setter + if (!($prop & 0b1000)) { + throw new MemberAccessException("Cannot write to a read-only property $class::\$$name."); + } + + $m = 'set' . ucfirst($name); + if ($prop & 0b10000) { + $trace = debug_backtrace(0, 1)[0]; // suppose this method is called from __call() + $loc = isset($trace['file'], $trace['line']) + ? " in $trace[file] on line $trace[line]" + : ''; + trigger_error("Property $class::\$$name is deprecated, use $class::$m() method$loc.", E_USER_DEPRECATED); + } + + $this->$m($value); + + } else { + ObjectHelpers::strictSet($class, $name); + } + } + + + /** + * @throws MemberAccessException + */ + public function __unset(string $name): void + { + $class = static::class; + if (!ObjectHelpers::hasProperty($class, $name)) { + throw new MemberAccessException("Cannot unset the property $class::\$$name."); + } + } + + + public function __isset(string $name): bool + { + return isset(ObjectHelpers::getMagicProperties(static::class)[$name]); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/StaticClass.php b/tools/.phpstan/vendor/nette/utils/src/StaticClass.php new file mode 100644 index 00000000000..46b27866902 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/StaticClass.php @@ -0,0 +1,24 @@ + + * @implements \ArrayAccess + */ +class ArrayHash extends \stdClass implements \ArrayAccess, \Countable, \IteratorAggregate +{ + /** + * Transforms array to ArrayHash. + * @param array $array + */ + public static function from(array $array, bool $recursive = true): static + { + $obj = new static; + foreach ($array as $key => $value) { + $obj->$key = $recursive && is_array($value) + ? static::from($value) + : $value; + } + + return $obj; + } + + + /** + * Returns an iterator over all items. + * @return \Iterator + */ + public function &getIterator(): \Iterator + { + foreach ((array) $this as $key => $foo) { + yield $key => $this->$key; + } + } + + + /** + * Returns items count. + */ + public function count(): int + { + return count((array) $this); + } + + + /** + * Replaces or appends an item. + * @param array-key $key + * @param T $value + */ + public function offsetSet($key, $value): void + { + if (!is_scalar($key)) { // prevents null + throw new Nette\InvalidArgumentException(sprintf('Key must be either a string or an integer, %s given.', get_debug_type($key))); + } + + $this->$key = $value; + } + + + /** + * Returns an item. + * @param array-key $key + * @return T + */ + #[\ReturnTypeWillChange] + public function offsetGet($key) + { + return $this->$key; + } + + + /** + * Determines whether an item exists. + * @param array-key $key + */ + public function offsetExists($key): bool + { + return isset($this->$key); + } + + + /** + * Removes the element from this list. + * @param array-key $key + */ + public function offsetUnset($key): void + { + unset($this->$key); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/ArrayList.php b/tools/.phpstan/vendor/nette/utils/src/Utils/ArrayList.php new file mode 100644 index 00000000000..98a50821973 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/ArrayList.php @@ -0,0 +1,135 @@ + + * @implements \ArrayAccess + */ +class ArrayList implements \ArrayAccess, \Countable, \IteratorAggregate +{ + private array $list = []; + + + /** + * Transforms array to ArrayList. + * @param list $array + */ + public static function from(array $array): static + { + if (!Arrays::isList($array)) { + throw new Nette\InvalidArgumentException('Array is not valid list.'); + } + + $obj = new static; + $obj->list = $array; + return $obj; + } + + + /** + * Returns an iterator over all items. + * @return \Iterator + */ + public function &getIterator(): \Iterator + { + foreach ($this->list as &$item) { + yield $item; + } + } + + + /** + * Returns items count. + */ + public function count(): int + { + return count($this->list); + } + + + /** + * Replaces or appends an item. + * @param int|null $index + * @param T $value + * @throws Nette\OutOfRangeException + */ + public function offsetSet($index, $value): void + { + if ($index === null) { + $this->list[] = $value; + + } elseif (!is_int($index) || $index < 0 || $index >= count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + + } else { + $this->list[$index] = $value; + } + } + + + /** + * Returns an item. + * @param int $index + * @return T + * @throws Nette\OutOfRangeException + */ + public function offsetGet($index): mixed + { + if (!is_int($index) || $index < 0 || $index >= count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + } + + return $this->list[$index]; + } + + + /** + * Determines whether an item exists. + * @param int $index + */ + public function offsetExists($index): bool + { + return is_int($index) && $index >= 0 && $index < count($this->list); + } + + + /** + * Removes the element at the specified position in this list. + * @param int $index + * @throws Nette\OutOfRangeException + */ + public function offsetUnset($index): void + { + if (!is_int($index) || $index < 0 || $index >= count($this->list)) { + throw new Nette\OutOfRangeException('Offset invalid or out of range'); + } + + array_splice($this->list, $index, 1); + } + + + /** + * Prepends an item. + * @param T $value + */ + public function prepend(mixed $value): void + { + $first = array_slice($this->list, 0, 1); + $this->offsetSet(0, $value); + array_splice($this->list, 1, 0, $first); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Arrays.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Arrays.php new file mode 100644 index 00000000000..986118c8983 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Arrays.php @@ -0,0 +1,551 @@ + $array + * @param array-key|array-key[] $key + * @param ?T $default + * @return ?T + * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided + */ + public static function get(array $array, string|int|array $key, mixed $default = null): mixed + { + foreach (is_array($key) ? $key : [$key] as $k) { + if (is_array($array) && array_key_exists($k, $array)) { + $array = $array[$k]; + } else { + if (func_num_args() < 3) { + throw new Nette\InvalidArgumentException("Missing item '$k'."); + } + + return $default; + } + } + + return $array; + } + + + /** + * Returns reference to array item. If the index does not exist, new one is created with value null. + * @template T + * @param array $array + * @param array-key|array-key[] $key + * @return ?T + * @throws Nette\InvalidArgumentException if traversed item is not an array + */ + public static function &getRef(array &$array, string|int|array $key): mixed + { + foreach (is_array($key) ? $key : [$key] as $k) { + if (is_array($array) || $array === null) { + $array = &$array[$k]; + } else { + throw new Nette\InvalidArgumentException('Traversed item is not an array.'); + } + } + + return $array; + } + + + /** + * Recursively merges two fields. It is useful, for example, for merging tree structures. It behaves as + * the + operator for array, ie. it adds a key/value pair from the second array to the first one and retains + * the value from the first array in the case of a key collision. + * @template T1 + * @template T2 + * @param array $array1 + * @param array $array2 + * @return array + */ + public static function mergeTree(array $array1, array $array2): array + { + $res = $array1 + $array2; + foreach (array_intersect_key($array1, $array2) as $k => $v) { + if (is_array($v) && is_array($array2[$k])) { + $res[$k] = self::mergeTree($v, $array2[$k]); + } + } + + return $res; + } + + + /** + * Returns zero-indexed position of given array key. Returns null if key is not found. + */ + public static function getKeyOffset(array $array, string|int $key): ?int + { + return Helpers::falseToNull(array_search(self::toKey($key), array_keys($array), strict: true)); + } + + + /** + * @deprecated use getKeyOffset() + */ + public static function searchKey(array $array, $key): ?int + { + return self::getKeyOffset($array, $key); + } + + + /** + * Tests an array for the presence of value. + */ + public static function contains(array $array, mixed $value): bool + { + return in_array($value, $array, true); + } + + + /** + * Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null. + * @template K of int|string + * @template V + * @param array $array + * @param ?callable(V, K, array): bool $predicate + * @return ?V + */ + public static function first(array $array, ?callable $predicate = null, ?callable $else = null): mixed + { + $key = self::firstKey($array, $predicate); + return $key === null + ? ($else ? $else() : null) + : $array[$key]; + } + + + /** + * Returns the last item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null. + * @template K of int|string + * @template V + * @param array $array + * @param ?callable(V, K, array): bool $predicate + * @return ?V + */ + public static function last(array $array, ?callable $predicate = null, ?callable $else = null): mixed + { + $key = self::lastKey($array, $predicate); + return $key === null + ? ($else ? $else() : null) + : $array[$key]; + } + + + /** + * Returns the key of first item (matching the specified predicate if given) or null if there is no such item. + * @template K of int|string + * @template V + * @param array $array + * @param ?callable(V, K, array): bool $predicate + * @return ?K + */ + public static function firstKey(array $array, ?callable $predicate = null): int|string|null + { + if (!$predicate) { + return array_key_first($array); + } + foreach ($array as $k => $v) { + if ($predicate($v, $k, $array)) { + return $k; + } + } + return null; + } + + + /** + * Returns the key of last item (matching the specified predicate if given) or null if there is no such item. + * @template K of int|string + * @template V + * @param array $array + * @param ?callable(V, K, array): bool $predicate + * @return ?K + */ + public static function lastKey(array $array, ?callable $predicate = null): int|string|null + { + return $predicate + ? self::firstKey(array_reverse($array, preserve_keys: true), $predicate) + : array_key_last($array); + } + + + /** + * Inserts the contents of the $inserted array into the $array immediately after the $key. + * If $key is null (or does not exist), it is inserted at the beginning. + */ + public static function insertBefore(array &$array, string|int|null $key, array $inserted): void + { + $offset = $key === null ? 0 : (int) self::getKeyOffset($array, $key); + $array = array_slice($array, 0, $offset, preserve_keys: true) + + $inserted + + array_slice($array, $offset, count($array), preserve_keys: true); + } + + + /** + * Inserts the contents of the $inserted array into the $array before the $key. + * If $key is null (or does not exist), it is inserted at the end. + */ + public static function insertAfter(array &$array, string|int|null $key, array $inserted): void + { + if ($key === null || ($offset = self::getKeyOffset($array, $key)) === null) { + $offset = count($array) - 1; + } + + $array = array_slice($array, 0, $offset + 1, preserve_keys: true) + + $inserted + + array_slice($array, $offset + 1, count($array), preserve_keys: true); + } + + + /** + * Renames key in array. + */ + public static function renameKey(array &$array, string|int $oldKey, string|int $newKey): bool + { + $offset = self::getKeyOffset($array, $oldKey); + if ($offset === null) { + return false; + } + + $val = &$array[$oldKey]; + $keys = array_keys($array); + $keys[$offset] = $newKey; + $array = array_combine($keys, $array); + $array[$newKey] = &$val; + return true; + } + + + /** + * Returns only those array items, which matches a regular expression $pattern. + * @param string[] $array + * @return string[] + */ + public static function grep( + array $array, + #[Language('RegExp')] + string $pattern, + bool|int $invert = false, + ): array + { + $flags = $invert ? PREG_GREP_INVERT : 0; + return Strings::pcre('preg_grep', [$pattern, $array, $flags]); + } + + + /** + * Transforms multidimensional array to flat array. + */ + public static function flatten(array $array, bool $preserveKeys = false): array + { + $res = []; + $cb = $preserveKeys + ? function ($v, $k) use (&$res): void { $res[$k] = $v; } + : function ($v) use (&$res): void { $res[] = $v; }; + array_walk_recursive($array, $cb); + return $res; + } + + + /** + * Checks if the array is indexed in ascending order of numeric keys from zero, a.k.a list. + * @return ($value is list ? true : false) + */ + public static function isList(mixed $value): bool + { + return is_array($value) && array_is_list($value); + } + + + /** + * Reformats table to associative tree. Path looks like 'field|field[]field->field=field'. + * @param string|string[] $path + */ + public static function associate(array $array, $path): array|\stdClass + { + $parts = is_array($path) + ? $path + : preg_split('#(\[\]|->|=|\|)#', $path, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY); + + if (!$parts || $parts === ['->'] || $parts[0] === '=' || $parts[0] === '|') { + throw new Nette\InvalidArgumentException("Invalid path '$path'."); + } + + $res = $parts[0] === '->' ? new \stdClass : []; + + foreach ($array as $rowOrig) { + $row = (array) $rowOrig; + $x = &$res; + + for ($i = 0; $i < count($parts); $i++) { + $part = $parts[$i]; + if ($part === '[]') { + $x = &$x[]; + + } elseif ($part === '=') { + if (isset($parts[++$i])) { + $x = $row[$parts[$i]]; + $row = null; + } + } elseif ($part === '->') { + if (isset($parts[++$i])) { + if ($x === null) { + $x = new \stdClass; + } + + $x = &$x->{$row[$parts[$i]]}; + } else { + $row = is_object($rowOrig) ? $rowOrig : (object) $row; + } + } elseif ($part !== '|') { + $x = &$x[(string) $row[$part]]; + } + } + + if ($x === null) { + $x = $row; + } + } + + return $res; + } + + + /** + * Normalizes array to associative array. Replace numeric keys with their values, the new value will be $filling. + */ + public static function normalize(array $array, mixed $filling = null): array + { + $res = []; + foreach ($array as $k => $v) { + $res[is_int($k) ? $v : $k] = is_int($k) ? $filling : $v; + } + + return $res; + } + + + /** + * Returns and removes the value of an item from an array. If it does not exist, it throws an exception, + * or returns $default, if provided. + * @template T + * @param array $array + * @param ?T $default + * @return ?T + * @throws Nette\InvalidArgumentException if item does not exist and default value is not provided + */ + public static function pick(array &$array, string|int $key, mixed $default = null): mixed + { + if (array_key_exists($key, $array)) { + $value = $array[$key]; + unset($array[$key]); + return $value; + + } elseif (func_num_args() < 3) { + throw new Nette\InvalidArgumentException("Missing item '$key'."); + + } else { + return $default; + } + } + + + /** + * Tests whether at least one element in the array passes the test implemented by the provided function. + * @template K of int|string + * @template V + * @param array $array + * @param callable(V, K, array): bool $predicate + */ + public static function some(iterable $array, callable $predicate): bool + { + foreach ($array as $k => $v) { + if ($predicate($v, $k, $array)) { + return true; + } + } + + return false; + } + + + /** + * Tests whether all elements in the array pass the test implemented by the provided function. + * @template K of int|string + * @template V + * @param array $array + * @param callable(V, K, array): bool $predicate + */ + public static function every(iterable $array, callable $predicate): bool + { + foreach ($array as $k => $v) { + if (!$predicate($v, $k, $array)) { + return false; + } + } + + return true; + } + + + /** + * Returns a new array containing all key-value pairs matching the given $predicate. + * @template K of int|string + * @template V + * @param array $array + * @param callable(V, K, array): bool $predicate + * @return array + */ + public static function filter(array $array, callable $predicate): array + { + $res = []; + foreach ($array as $k => $v) { + if ($predicate($v, $k, $array)) { + $res[$k] = $v; + } + } + return $res; + } + + + /** + * Returns an array containing the original keys and results of applying the given transform function to each element. + * @template K of int|string + * @template V + * @template R + * @param array $array + * @param callable(V, K, array): R $transformer + * @return array + */ + public static function map(iterable $array, callable $transformer): array + { + $res = []; + foreach ($array as $k => $v) { + $res[$k] = $transformer($v, $k, $array); + } + + return $res; + } + + + /** + * Returns an array containing new keys and values generated by applying the given transform function to each element. + * If the function returns null, the element is skipped. + * @template K of int|string + * @template V + * @template ResK of int|string + * @template ResV + * @param array $array + * @param callable(V, K, array): ?array{ResK, ResV} $transformer + * @return array + */ + public static function mapWithKeys(array $array, callable $transformer): array + { + $res = []; + foreach ($array as $k => $v) { + $pair = $transformer($v, $k, $array); + if ($pair) { + $res[$pair[0]] = $pair[1]; + } + } + + return $res; + } + + + /** + * Invokes all callbacks and returns array of results. + * @param callable[] $callbacks + */ + public static function invoke(iterable $callbacks, ...$args): array + { + $res = []; + foreach ($callbacks as $k => $cb) { + $res[$k] = $cb(...$args); + } + + return $res; + } + + + /** + * Invokes method on every object in an array and returns array of results. + * @param object[] $objects + */ + public static function invokeMethod(iterable $objects, string $method, ...$args): array + { + $res = []; + foreach ($objects as $k => $obj) { + $res[$k] = $obj->$method(...$args); + } + + return $res; + } + + + /** + * Copies the elements of the $array array to the $object object and then returns it. + * @template T of object + * @param T $object + * @return T + */ + public static function toObject(iterable $array, object $object): object + { + foreach ($array as $k => $v) { + $object->$k = $v; + } + + return $object; + } + + + /** + * Converts value to array key. + */ + public static function toKey(mixed $value): int|string + { + return key(@[$value => null]); + } + + + /** + * Returns copy of the $array where every item is converted to string + * and prefixed by $prefix and suffixed by $suffix. + * @param string[] $array + * @return string[] + */ + public static function wrap(array $array, string $prefix = '', string $suffix = ''): array + { + $res = []; + foreach ($array as $k => $v) { + $res[$k] = $prefix . $v . $suffix; + } + + return $res; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Callback.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Callback.php new file mode 100644 index 00000000000..7d384f25e61 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Callback.php @@ -0,0 +1,137 @@ +getClosureScopeClass()?->name; + if (str_ends_with($r->name, '}')) { + return $closure; + + } elseif (($obj = $r->getClosureThis()) && $obj::class === $class) { + return [$obj, $r->name]; + + } elseif ($class) { + return [$class, $r->name]; + + } else { + return $r->name; + } + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/DateTime.php b/tools/.phpstan/vendor/nette/utils/src/Utils/DateTime.php new file mode 100644 index 00000000000..6191223f592 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/DateTime.php @@ -0,0 +1,209 @@ +setTimestamp((int) $time); + + } else { // textual or null + return new static((string) $time); + } + } + + + /** + * Creates DateTime object. + * @throws \Exception if the date and time are not valid. + */ + public static function fromParts( + int $year, + int $month, + int $day, + int $hour = 0, + int $minute = 0, + float $second = 0.0, + ): static + { + $sec = (int) floor($second); + return (new static('')) + ->setDate($year, $month, $day) + ->setTime($hour, $minute, $sec, (int) round(($second - $sec) * 1e6)); + } + + + /** + * Returns a new DateTime object formatted according to the specified format. + */ + public static function createFromFormat( + string $format, + string $datetime, + string|\DateTimeZone|null $timezone = null, + ): static|false + { + if (is_string($timezone)) { + $timezone = new \DateTimeZone($timezone); + } + + $date = parent::createFromFormat($format, $datetime, $timezone); + return $date ? static::from($date) : false; + } + + + public function __construct(string $datetime = 'now', ?\DateTimeZone $timezone = null) + { + $this->apply($datetime, $timezone, true); + } + + + public function modify(string $modifier): static + { + $this->apply($modifier); + return $this; + } + + + public function setDate(int $year, int $month, int $day): static + { + if (!checkdate($month, $day, $year)) { + throw new \Exception(sprintf('The date %04d-%02d-%02d is not valid.', $year, $month, $day)); + } + return parent::setDate($year, $month, $day); + } + + + public function setTime(int $hour, int $minute, int $second = 0, int $microsecond = 0): static + { + if ( + $hour < 0 || $hour > 23 + || $minute < 0 || $minute > 59 + || $second < 0 || $second >= 60 + || $microsecond < 0 || $microsecond >= 1_000_000 + ) { + throw new \Exception(sprintf('The time %02d:%02d:%08.5F is not valid.', $hour, $minute, $second + $microsecond / 1_000_000)); + } + return parent::setTime($hour, $minute, $second, $microsecond); + } + + + /** + * Converts a relative time string (e.g. '10 minut') to seconds. + */ + public static function relativeToSeconds(string $relativeTime): int + { + return (new self('@0 ' . $relativeTime)) + ->getTimestamp(); + } + + + private function apply(string $datetime, $timezone = null, bool $ctr = false): void + { + $relPart = ''; + $absPart = preg_replace_callback( + '/[+-]?\s*\d+\s+((microsecond|millisecond|[mµu]sec)s?|[mµ]s|sec(ond)?s?|min(ute)?s?|hours?)(\s+ago)?\b/iu', + function ($m) use (&$relPart) { + $relPart .= $m[0] . ' '; + return ''; + }, + $datetime, + ); + + if ($ctr) { + parent::__construct($absPart, $timezone); + $this->handleErrors($datetime); + } elseif (trim($absPart)) { + parent::modify($absPart) && $this->handleErrors($datetime); + } + + if ($relPart) { + $timezone ??= $this->getTimezone(); + $this->setTimezone(new \DateTimeZone('UTC')); + parent::modify($relPart) && $this->handleErrors($datetime); + $this->setTimezone($timezone); + } + } + + + /** + * Returns JSON representation in ISO 8601 (used by JavaScript). + */ + public function jsonSerialize(): string + { + return $this->format('c'); + } + + + /** + * Returns the date and time in the format 'Y-m-d H:i:s'. + */ + public function __toString(): string + { + return $this->format('Y-m-d H:i:s'); + } + + + /** + * You'd better use: (clone $dt)->modify(...) + */ + public function modifyClone(string $modify = ''): static + { + $dolly = clone $this; + return $modify ? $dolly->modify($modify) : $dolly; + } + + + private function handleErrors(string $value): void + { + $errors = self::getLastErrors(); + $errors = array_merge($errors['errors'] ?? [], $errors['warnings'] ?? []); + if ($errors) { + throw new \Exception(implode(', ', $errors) . " '$value'"); + } + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/FileInfo.php b/tools/.phpstan/vendor/nette/utils/src/Utils/FileInfo.php new file mode 100644 index 00000000000..59dd722717c --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/FileInfo.php @@ -0,0 +1,70 @@ +setInfoClass(static::class); + $this->relativePath = $relativePath; + } + + + /** + * Returns the relative directory path. + */ + public function getRelativePath(): string + { + return $this->relativePath; + } + + + /** + * Returns the relative path including file name. + */ + public function getRelativePathname(): string + { + return ($this->relativePath === '' ? '' : $this->relativePath . DIRECTORY_SEPARATOR) + . $this->getBasename(); + } + + + /** + * Returns the contents of the file. + * @throws Nette\IOException + */ + public function read(): string + { + return FileSystem::read($this->getPathname()); + } + + + /** + * Writes the contents to the file. + * @throws Nette\IOException + */ + public function write(string $content): void + { + FileSystem::write($this->getPathname(), $content); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/FileSystem.php b/tools/.phpstan/vendor/nette/utils/src/Utils/FileSystem.php new file mode 100644 index 00000000000..8adb21e6634 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/FileSystem.php @@ -0,0 +1,341 @@ +getPathname()); + } + + foreach ($iterator = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($origin, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::SELF_FIRST) as $item) { + if ($item->isDir()) { + static::createDir($target . '/' . $iterator->getSubPathName()); + } else { + static::copy($item->getPathname(), $target . '/' . $iterator->getSubPathName()); + } + } + } else { + static::createDir(dirname($target)); + if (@stream_copy_to_stream(static::open($origin, 'rb'), static::open($target, 'wb')) === false) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to copy file '%s' to '%s'. %s", + self::normalizePath($origin), + self::normalizePath($target), + Helpers::getLastError(), + )); + } + } + } + + + /** + * Opens file and returns resource. + * @return resource + * @throws Nette\IOException on error occurred + */ + public static function open(string $path, string $mode) + { + $f = @fopen($path, $mode); // @ is escalated to exception + if (!$f) { + throw new Nette\IOException(sprintf( + "Unable to open file '%s'. %s", + self::normalizePath($path), + Helpers::getLastError(), + )); + } + return $f; + } + + + /** + * Deletes a file or an entire directory if exists. If the directory is not empty, it deletes its contents first. + * @throws Nette\IOException on error occurred + */ + public static function delete(string $path): void + { + if (is_file($path) || is_link($path)) { + $func = DIRECTORY_SEPARATOR === '\\' && is_dir($path) ? 'rmdir' : 'unlink'; + if (!@$func($path)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to delete '%s'. %s", + self::normalizePath($path), + Helpers::getLastError(), + )); + } + } elseif (is_dir($path)) { + foreach (new \FilesystemIterator($path) as $item) { + static::delete($item->getPathname()); + } + + if (!@rmdir($path)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to delete directory '%s'. %s", + self::normalizePath($path), + Helpers::getLastError(), + )); + } + } + } + + + /** + * Renames or moves a file or a directory. Overwrites existing files and directories by default. + * @throws Nette\IOException on error occurred + * @throws Nette\InvalidStateException if $overwrite is set to false and destination already exists + */ + public static function rename(string $origin, string $target, bool $overwrite = true): void + { + if (!$overwrite && file_exists($target)) { + throw new Nette\InvalidStateException(sprintf("File or directory '%s' already exists.", self::normalizePath($target))); + + } elseif (!file_exists($origin)) { + throw new Nette\IOException(sprintf("File or directory '%s' not found.", self::normalizePath($origin))); + + } else { + static::createDir(dirname($target)); + if (realpath($origin) !== realpath($target)) { + static::delete($target); + } + + if (!@rename($origin, $target)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to rename file or directory '%s' to '%s'. %s", + self::normalizePath($origin), + self::normalizePath($target), + Helpers::getLastError(), + )); + } + } + } + + + /** + * Reads the content of a file. + * @throws Nette\IOException on error occurred + */ + public static function read(string $file): string + { + $content = @file_get_contents($file); // @ is escalated to exception + if ($content === false) { + throw new Nette\IOException(sprintf( + "Unable to read file '%s'. %s", + self::normalizePath($file), + Helpers::getLastError(), + )); + } + + return $content; + } + + + /** + * Reads the file content line by line. Because it reads continuously as we iterate over the lines, + * it is possible to read files larger than the available memory. + * @return \Generator + * @throws Nette\IOException on error occurred + */ + public static function readLines(string $file, bool $stripNewLines = true): \Generator + { + return (function ($f) use ($file, $stripNewLines) { + $counter = 0; + do { + $line = Callback::invokeSafe('fgets', [$f], fn($error) => throw new Nette\IOException(sprintf( + "Unable to read file '%s'. %s", + self::normalizePath($file), + $error, + ))); + if ($line === false) { + fclose($f); + break; + } + if ($stripNewLines) { + $line = rtrim($line, "\r\n"); + } + + yield $counter++ => $line; + + } while (true); + })(static::open($file, 'r')); + } + + + /** + * Writes the string to a file. + * @throws Nette\IOException on error occurred + */ + public static function write(string $file, string $content, ?int $mode = 0o666): void + { + static::createDir(dirname($file)); + if (@file_put_contents($file, $content) === false) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to write file '%s'. %s", + self::normalizePath($file), + Helpers::getLastError(), + )); + } + + if ($mode !== null && !@chmod($file, $mode)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to chmod file '%s' to mode %s. %s", + self::normalizePath($file), + decoct($mode), + Helpers::getLastError(), + )); + } + } + + + /** + * Sets file permissions to `$fileMode` or directory permissions to `$dirMode`. + * Recursively traverses and sets permissions on the entire contents of the directory as well. + * @throws Nette\IOException on error occurred + */ + public static function makeWritable(string $path, int $dirMode = 0o777, int $fileMode = 0o666): void + { + if (is_file($path)) { + if (!@chmod($path, $fileMode)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to chmod file '%s' to mode %s. %s", + self::normalizePath($path), + decoct($fileMode), + Helpers::getLastError(), + )); + } + } elseif (is_dir($path)) { + foreach (new \FilesystemIterator($path) as $item) { + static::makeWritable($item->getPathname(), $dirMode, $fileMode); + } + + if (!@chmod($path, $dirMode)) { // @ is escalated to exception + throw new Nette\IOException(sprintf( + "Unable to chmod directory '%s' to mode %s. %s", + self::normalizePath($path), + decoct($dirMode), + Helpers::getLastError(), + )); + } + } else { + throw new Nette\IOException(sprintf("File or directory '%s' not found.", self::normalizePath($path))); + } + } + + + /** + * Determines if the path is absolute. + */ + public static function isAbsolute(string $path): bool + { + return (bool) preg_match('#([a-z]:)?[/\\\]|[a-z][a-z0-9+.-]*://#Ai', $path); + } + + + /** + * Normalizes `..` and `.` and directory separators in path. + */ + public static function normalizePath(string $path): string + { + $parts = $path === '' ? [] : preg_split('~[/\\\]+~', $path); + $res = []; + foreach ($parts as $part) { + if ($part === '..' && $res && end($res) !== '..' && end($res) !== '') { + array_pop($res); + } elseif ($part !== '.') { + $res[] = $part; + } + } + + return $res === [''] + ? DIRECTORY_SEPARATOR + : implode(DIRECTORY_SEPARATOR, $res); + } + + + /** + * Joins all segments of the path and normalizes the result. + */ + public static function joinPaths(string ...$paths): string + { + return self::normalizePath(implode('/', $paths)); + } + + + /** + * Resolves a path against a base path. If the path is absolute, returns it directly, if it's relative, joins it with the base path. + */ + public static function resolvePath(string $basePath, string $path): string + { + return match (true) { + self::isAbsolute($path) => self::platformSlashes($path), + $path === '' => self::platformSlashes($basePath), + default => self::joinPaths($basePath, $path), + }; + } + + + /** + * Converts backslashes to slashes. + */ + public static function unixSlashes(string $path): string + { + return strtr($path, '\\', '/'); + } + + + /** + * Converts slashes to platform-specific directory separators. + */ + public static function platformSlashes(string $path): string + { + return DIRECTORY_SEPARATOR === '/' + ? strtr($path, '\\', '/') + : str_replace(':\\\\', '://', strtr($path, '/', '\\')); // protocol:// + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Finder.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Finder.php new file mode 100644 index 00000000000..2f5f7d16be9 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Finder.php @@ -0,0 +1,510 @@ +size('> 10kB') + * ->from('.') + * ->exclude('temp'); + * + * @implements \IteratorAggregate + */ +class Finder implements \IteratorAggregate +{ + /** @var array */ + private array $find = []; + + /** @var string[] */ + private array $in = []; + + /** @var \Closure[] */ + private array $filters = []; + + /** @var \Closure[] */ + private array $descentFilters = []; + + /** @var array */ + private array $appends = []; + private bool $childFirst = false; + + /** @var ?callable */ + private $sort; + private int $maxDepth = -1; + private bool $ignoreUnreadableDirs = true; + + + /** + * Begins search for files and directories matching mask. + */ + public static function find(string|array $masks = ['*']): static + { + $masks = is_array($masks) ? $masks : func_get_args(); // compatibility with variadic + return (new static)->addMask($masks, 'dir')->addMask($masks, 'file'); + } + + + /** + * Begins search for files matching mask. + */ + public static function findFiles(string|array $masks = ['*']): static + { + $masks = is_array($masks) ? $masks : func_get_args(); // compatibility with variadic + return (new static)->addMask($masks, 'file'); + } + + + /** + * Begins search for directories matching mask. + */ + public static function findDirectories(string|array $masks = ['*']): static + { + $masks = is_array($masks) ? $masks : func_get_args(); // compatibility with variadic + return (new static)->addMask($masks, 'dir'); + } + + + /** + * Finds files matching the specified masks. + */ + public function files(string|array $masks = ['*']): static + { + return $this->addMask((array) $masks, 'file'); + } + + + /** + * Finds directories matching the specified masks. + */ + public function directories(string|array $masks = ['*']): static + { + return $this->addMask((array) $masks, 'dir'); + } + + + private function addMask(array $masks, string $mode): static + { + foreach ($masks as $mask) { + $mask = FileSystem::unixSlashes($mask); + if ($mode === 'dir') { + $mask = rtrim($mask, '/'); + } + if ($mask === '' || ($mode === 'file' && str_ends_with($mask, '/'))) { + throw new Nette\InvalidArgumentException("Invalid mask '$mask'"); + } + if (str_starts_with($mask, '**/')) { + $mask = substr($mask, 3); + } + $this->find[] = [$mask, $mode]; + } + return $this; + } + + + /** + * Searches in the given directories. Wildcards are allowed. + */ + public function in(string|array $paths): static + { + $paths = is_array($paths) ? $paths : func_get_args(); // compatibility with variadic + $this->addLocation($paths, ''); + return $this; + } + + + /** + * Searches recursively from the given directories. Wildcards are allowed. + */ + public function from(string|array $paths): static + { + $paths = is_array($paths) ? $paths : func_get_args(); // compatibility with variadic + $this->addLocation($paths, '/**'); + return $this; + } + + + private function addLocation(array $paths, string $ext): void + { + foreach ($paths as $path) { + if ($path === '') { + throw new Nette\InvalidArgumentException("Invalid directory '$path'"); + } + $path = rtrim(FileSystem::unixSlashes($path), '/'); + $this->in[] = $path . $ext; + } + } + + + /** + * Lists directory's contents before the directory itself. By default, this is disabled. + */ + public function childFirst(bool $state = true): static + { + $this->childFirst = $state; + return $this; + } + + + /** + * Ignores unreadable directories. By default, this is enabled. + */ + public function ignoreUnreadableDirs(bool $state = true): static + { + $this->ignoreUnreadableDirs = $state; + return $this; + } + + + /** + * Set a compare function for sorting directory entries. The function will be called to sort entries from the same directory. + * @param callable(FileInfo, FileInfo): int $callback + */ + public function sortBy(callable $callback): static + { + $this->sort = $callback; + return $this; + } + + + /** + * Sorts files in each directory naturally by name. + */ + public function sortByName(): static + { + $this->sort = fn(FileInfo $a, FileInfo $b): int => strnatcmp($a->getBasename(), $b->getBasename()); + return $this; + } + + + /** + * Adds the specified paths or appends a new finder that returns. + */ + public function append(string|array|null $paths = null): static + { + if ($paths === null) { + return $this->appends[] = new static; + } + + $this->appends = array_merge($this->appends, (array) $paths); + return $this; + } + + + /********************* filtering ****************d*g**/ + + + /** + * Skips entries that matches the given masks relative to the ones defined with the in() or from() methods. + */ + public function exclude(string|array $masks): static + { + $masks = is_array($masks) ? $masks : func_get_args(); // compatibility with variadic + foreach ($masks as $mask) { + $mask = FileSystem::unixSlashes($mask); + if (!preg_match('~^/?(\*\*/)?(.+)(/\*\*|/\*|/|)$~D', $mask, $m)) { + throw new Nette\InvalidArgumentException("Invalid mask '$mask'"); + } + $end = $m[3]; + $re = $this->buildPattern($m[2]); + $filter = fn(FileInfo $file): bool => ($end && !$file->isDir()) + || !preg_match($re, FileSystem::unixSlashes($file->getRelativePathname())); + + $this->descentFilter($filter); + if ($end !== '/*') { + $this->filter($filter); + } + } + + return $this; + } + + + /** + * Yields only entries which satisfy the given filter. + * @param callable(FileInfo): bool $callback + */ + public function filter(callable $callback): static + { + $this->filters[] = \Closure::fromCallable($callback); + return $this; + } + + + /** + * It descends only to directories that match the specified filter. + * @param callable(FileInfo): bool $callback + */ + public function descentFilter(callable $callback): static + { + $this->descentFilters[] = \Closure::fromCallable($callback); + return $this; + } + + + /** + * Sets the maximum depth of entries. + */ + public function limitDepth(?int $depth): static + { + $this->maxDepth = $depth ?? -1; + return $this; + } + + + /** + * Restricts the search by size. $operator accepts "[operator] [size] [unit]" example: >=10kB + */ + public function size(string $operator, ?int $size = null): static + { + if (func_num_args() === 1) { // in $operator is predicate + if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?((?:\d*\.)?\d+)\s*(K|M|G|)B?$#Di', $operator, $matches)) { + throw new Nette\InvalidArgumentException('Invalid size predicate format.'); + } + + [, $operator, $size, $unit] = $matches; + $units = ['' => 1, 'k' => 1e3, 'm' => 1e6, 'g' => 1e9]; + $size *= $units[strtolower($unit)]; + $operator = $operator ?: '='; + } + + return $this->filter(fn(FileInfo $file): bool => !$file->isFile() || Helpers::compare($file->getSize(), $operator, $size)); + } + + + /** + * Restricts the search by modified time. $operator accepts "[operator] [date]" example: >1978-01-23 + */ + public function date(string $operator, string|int|\DateTimeInterface|null $date = null): static + { + if (func_num_args() === 1) { // in $operator is predicate + if (!preg_match('#^(?:([=<>!]=?|<>)\s*)?(.+)$#Di', $operator, $matches)) { + throw new Nette\InvalidArgumentException('Invalid date predicate format.'); + } + + [, $operator, $date] = $matches; + $operator = $operator ?: '='; + } + + $date = DateTime::from($date)->getTimestamp(); + return $this->filter(fn(FileInfo $file): bool => !$file->isFile() || Helpers::compare($file->getMTime(), $operator, $date)); + } + + + /********************* iterator generator ****************d*g**/ + + + /** + * Returns an array with all found files and directories. + * @return list + */ + public function collect(): array + { + return iterator_to_array($this->getIterator(), preserve_keys: false); + } + + + /** @return \Generator */ + public function getIterator(): \Generator + { + $plan = $this->buildPlan(); + foreach ($plan as $dir => $searches) { + yield from $this->traverseDir($dir, $searches); + } + + foreach ($this->appends as $item) { + if ($item instanceof self) { + yield from $item->getIterator(); + } else { + $item = FileSystem::platformSlashes($item); + yield $item => new FileInfo($item); + } + } + } + + + /** + * @param array $searches + * @param string[] $subdirs + * @return \Generator + */ + private function traverseDir(string $dir, array $searches, array $subdirs = []): \Generator + { + if ($this->maxDepth >= 0 && count($subdirs) > $this->maxDepth) { + return; + } elseif (!is_dir($dir)) { + throw new Nette\InvalidStateException(sprintf("Directory '%s' does not exist.", rtrim($dir, '/\\'))); + } + + try { + $pathNames = new \FilesystemIterator($dir, \FilesystemIterator::FOLLOW_SYMLINKS | \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::UNIX_PATHS); + } catch (\UnexpectedValueException $e) { + if ($this->ignoreUnreadableDirs) { + return; + } else { + throw new Nette\InvalidStateException($e->getMessage()); + } + } + + $files = $this->convertToFiles($pathNames, implode('/', $subdirs), FileSystem::isAbsolute($dir)); + + if ($this->sort) { + $files = iterator_to_array($files); + usort($files, $this->sort); + } + + foreach ($files as $file) { + $pathName = $file->getPathname(); + $cache = $subSearch = []; + + if ($file->isDir()) { + foreach ($searches as $search) { + if ($search->recursive && $this->proveFilters($this->descentFilters, $file, $cache)) { + $subSearch[] = $search; + } + } + } + + if ($this->childFirst && $subSearch) { + yield from $this->traverseDir($pathName, $subSearch, array_merge($subdirs, [$file->getBasename()])); + } + + $relativePathname = FileSystem::unixSlashes($file->getRelativePathname()); + foreach ($searches as $search) { + if ( + "is_$search->mode"(Helpers::IsWindows && $file->isLink() ? $file->getLinkTarget() : $file->getPathname()) + && preg_match($search->pattern, $relativePathname) + && $this->proveFilters($this->filters, $file, $cache) + ) { + yield $pathName => $file; + break; + } + } + + if (!$this->childFirst && $subSearch) { + yield from $this->traverseDir($pathName, $subSearch, array_merge($subdirs, [$file->getBasename()])); + } + } + } + + + private function convertToFiles(iterable $pathNames, string $relativePath, bool $absolute): \Generator + { + foreach ($pathNames as $pathName) { + if (!$absolute) { + $pathName = preg_replace('~\.?/~A', '', $pathName); + } + $pathName = FileSystem::platformSlashes($pathName); + yield new FileInfo($pathName, $relativePath); + } + } + + + private function proveFilters(array $filters, FileInfo $file, array &$cache): bool + { + foreach ($filters as $filter) { + $res = &$cache[spl_object_id($filter)]; + $res ??= $filter($file); + if (!$res) { + return false; + } + } + + return true; + } + + + /** @return array> */ + private function buildPlan(): array + { + $plan = $dirCache = []; + foreach ($this->find as [$mask, $mode]) { + $splits = []; + if (FileSystem::isAbsolute($mask)) { + if ($this->in) { + throw new Nette\InvalidStateException("You cannot combine the absolute path in the mask '$mask' and the directory to search '{$this->in[0]}'."); + } + $splits[] = self::splitRecursivePart($mask); + } else { + foreach ($this->in ?: ['.'] as $in) { + $in = strtr($in, ['[' => '[[]', ']' => '[]]']); // in path, do not treat [ and ] as a pattern by glob() + $splits[] = self::splitRecursivePart($in . '/' . $mask); + } + } + + foreach ($splits as [$base, $rest, $recursive]) { + $base = $base === '' ? '.' : $base; + $dirs = $dirCache[$base] ??= strpbrk($base, '*?[') + ? glob($base, GLOB_NOSORT | GLOB_ONLYDIR | GLOB_NOESCAPE) + : [strtr($base, ['[[]' => '[', '[]]' => ']'])]; // unescape [ and ] + + if (!$dirs) { + throw new Nette\InvalidStateException(sprintf("Directory '%s' does not exist.", rtrim($base, '/\\'))); + } + + $search = (object) ['pattern' => $this->buildPattern($rest), 'mode' => $mode, 'recursive' => $recursive]; + foreach ($dirs as $dir) { + $plan[$dir][] = $search; + } + } + } + + return $plan; + } + + + /** + * Since glob() does not know ** wildcard, we divide the path into a part for glob and a part for manual traversal. + */ + private static function splitRecursivePart(string $path): array + { + $a = strrpos($path, '/'); + $parts = preg_split('~(?<=^|/)\*\*($|/)~', substr($path, 0, $a + 1), 2); + return isset($parts[1]) + ? [$parts[0], $parts[1] . substr($path, $a + 1), true] + : [$parts[0], substr($path, $a + 1), false]; + } + + + /** + * Converts wildcards to regular expression. + */ + private function buildPattern(string $mask): string + { + if ($mask === '*') { + return '##'; + } elseif (str_starts_with($mask, './')) { + $anchor = '^'; + $mask = substr($mask, 2); + } else { + $anchor = '(?:^|/)'; + } + + $pattern = strtr( + preg_quote($mask, '#'), + [ + '\*\*/' => '(.+/)?', + '\*' => '[^/]*', + '\?' => '[^/]', + '\[\!' => '[^', + '\[' => '[', + '\]' => ']', + '\-' => '-', + ], + ); + return '#' . $anchor . $pattern . '$#D' . (Helpers::IsWindows ? 'i' : ''); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Floats.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Floats.php new file mode 100644 index 00000000000..ed78a55039b --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Floats.php @@ -0,0 +1,108 @@ + $b it returns 1 + * @throws \LogicException if one of parameters is NAN + */ + public static function compare(float $a, float $b): int + { + if (is_nan($a) || is_nan($b)) { + throw new \LogicException('Trying to compare NAN'); + + } elseif (!is_finite($a) && !is_finite($b) && $a === $b) { + return 0; + } + + $diff = abs($a - $b); + if (($diff < self::Epsilon || ($diff / max(abs($a), abs($b)) < self::Epsilon))) { + return 0; + } + + return $a < $b ? -1 : 1; + } + + + /** + * Returns true if $a = $b + * @throws \LogicException if one of parameters is NAN + */ + public static function areEqual(float $a, float $b): bool + { + return self::compare($a, $b) === 0; + } + + + /** + * Returns true if $a < $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isLessThan(float $a, float $b): bool + { + return self::compare($a, $b) < 0; + } + + + /** + * Returns true if $a <= $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isLessThanOrEqualTo(float $a, float $b): bool + { + return self::compare($a, $b) <= 0; + } + + + /** + * Returns true if $a > $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isGreaterThan(float $a, float $b): bool + { + return self::compare($a, $b) > 0; + } + + + /** + * Returns true if $a >= $b + * @throws \LogicException if one of parameters is NAN + */ + public static function isGreaterThanOrEqualTo(float $a, float $b): bool + { + return self::compare($a, $b) >= 0; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Helpers.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Helpers.php new file mode 100644 index 00000000000..c7d78943d94 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Helpers.php @@ -0,0 +1,121 @@ + ''); + try { + $func(); + return ob_get_clean(); + } catch (\Throwable $e) { + ob_end_clean(); + throw $e; + } + } + + + /** + * Returns the last occurred PHP error or an empty string if no error occurred. Unlike error_get_last(), + * it is nit affected by the PHP directive html_errors and always returns text, not HTML. + */ + public static function getLastError(): string + { + $message = error_get_last()['message'] ?? ''; + $message = ini_get('html_errors') ? Html::htmlToText($message) : $message; + $message = preg_replace('#^\w+\(.*?\): #', '', $message); + return $message; + } + + + /** + * Converts false to null, does not change other values. + */ + public static function falseToNull(mixed $value): mixed + { + return $value === false ? null : $value; + } + + + /** + * Returns value clamped to the inclusive range of min and max. + */ + public static function clamp(int|float $value, int|float $min, int|float $max): int|float + { + if ($min > $max) { + throw new Nette\InvalidArgumentException("Minimum ($min) is not less than maximum ($max)."); + } + + return min(max($value, $min), $max); + } + + + /** + * Looks for a string from possibilities that is most similar to value, but not the same (for 8-bit encoding). + * @param string[] $possibilities + */ + public static function getSuggestion(array $possibilities, string $value): ?string + { + $best = null; + $min = (strlen($value) / 4 + 1) * 10 + .1; + foreach (array_unique($possibilities) as $item) { + if ($item !== $value && ($len = levenshtein($item, $value, 10, 11, 10)) < $min) { + $min = $len; + $best = $item; + } + } + + return $best; + } + + + /** + * Compares two values in the same way that PHP does. Recognizes operators: >, >=, <, <=, =, ==, ===, !=, !==, <> + */ + public static function compare(mixed $left, string $operator, mixed $right): bool + { + return match ($operator) { + '>' => $left > $right, + '>=' => $left >= $right, + '<' => $left < $right, + '<=' => $left <= $right, + '=', '==' => $left == $right, + '===' => $left === $right, + '!=', '<>' => $left != $right, + '!==' => $left !== $right, + default => throw new Nette\InvalidArgumentException("Unknown operator '$operator'"), + }; + } + + + /** + * Splits a class name into namespace and short class name. + * @return array{string, string} + */ + public static function splitClassName(string $name): array + { + return ($pos = strrpos($name, '\\')) === false + ? ['', $name] + : [substr($name, 0, $pos), substr($name, $pos + 1)]; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Html.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Html.php new file mode 100644 index 00000000000..3a57de5ed59 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Html.php @@ -0,0 +1,837 @@ + element's attributes */ + public array $attrs = []; + + /** void elements */ + public static array $emptyElements = [ + 'img' => 1, 'hr' => 1, 'br' => 1, 'input' => 1, 'meta' => 1, 'area' => 1, 'embed' => 1, 'keygen' => 1, + 'source' => 1, 'base' => 1, 'col' => 1, 'link' => 1, 'param' => 1, 'basefont' => 1, 'frame' => 1, + 'isindex' => 1, 'wbr' => 1, 'command' => 1, 'track' => 1, + ]; + + /** @var array nodes */ + protected array $children = []; + + /** element's name */ + private string $name = ''; + + private bool $isEmpty = false; + + + /** + * Constructs new HTML element. + * @param array|string $attrs element's attributes or plain text content + */ + public static function el(?string $name = null, array|string|null $attrs = null): static + { + $el = new static; + $parts = explode(' ', (string) $name, 2); + $el->setName($parts[0]); + + if (is_array($attrs)) { + $el->attrs = $attrs; + + } elseif ($attrs !== null) { + $el->setText($attrs); + } + + if (isset($parts[1])) { + foreach (Strings::matchAll($parts[1] . ' ', '#([a-z0-9:-]+)(?:=(["\'])?(.*?)(?(2)\2|\s))?#i') as $m) { + $el->attrs[$m[1]] = $m[3] ?? true; + } + } + + return $el; + } + + + /** + * Returns an object representing HTML text. + */ + public static function fromHtml(string $html): static + { + return (new static)->setHtml($html); + } + + + /** + * Returns an object representing plain text. + */ + public static function fromText(string $text): static + { + return (new static)->setText($text); + } + + + /** + * Converts to HTML. + */ + final public function toHtml(): string + { + return $this->render(); + } + + + /** + * Converts to plain text. + */ + final public function toText(): string + { + return $this->getText(); + } + + + /** + * Converts given HTML code to plain text. + */ + public static function htmlToText(string $html): string + { + return html_entity_decode(strip_tags($html), ENT_QUOTES | ENT_HTML5, 'UTF-8'); + } + + + /** + * Changes element's name. + */ + final public function setName(string $name, ?bool $isEmpty = null): static + { + $this->name = $name; + $this->isEmpty = $isEmpty ?? isset(static::$emptyElements[$name]); + return $this; + } + + + /** + * Returns element's name. + */ + final public function getName(): string + { + return $this->name; + } + + + /** + * Is element empty? + */ + final public function isEmpty(): bool + { + return $this->isEmpty; + } + + + /** + * Sets multiple attributes. + */ + public function addAttributes(array $attrs): static + { + $this->attrs = array_merge($this->attrs, $attrs); + return $this; + } + + + /** + * Appends value to element's attribute. + */ + public function appendAttribute(string $name, mixed $value, mixed $option = true): static + { + if (is_array($value)) { + $prev = isset($this->attrs[$name]) ? (array) $this->attrs[$name] : []; + $this->attrs[$name] = $value + $prev; + + } elseif ((string) $value === '') { + $tmp = &$this->attrs[$name]; // appending empty value? -> ignore, but ensure it exists + + } elseif (!isset($this->attrs[$name]) || is_array($this->attrs[$name])) { // needs array + $this->attrs[$name][$value] = $option; + + } else { + $this->attrs[$name] = [$this->attrs[$name] => true, $value => $option]; + } + + return $this; + } + + + /** + * Sets element's attribute. + */ + public function setAttribute(string $name, mixed $value): static + { + $this->attrs[$name] = $value; + return $this; + } + + + /** + * Returns element's attribute. + */ + public function getAttribute(string $name): mixed + { + return $this->attrs[$name] ?? null; + } + + + /** + * Unsets element's attribute. + */ + public function removeAttribute(string $name): static + { + unset($this->attrs[$name]); + return $this; + } + + + /** + * Unsets element's attributes. + */ + public function removeAttributes(array $attributes): static + { + foreach ($attributes as $name) { + unset($this->attrs[$name]); + } + + return $this; + } + + + /** + * Overloaded setter for element's attribute. + */ + final public function __set(string $name, mixed $value): void + { + $this->attrs[$name] = $value; + } + + + /** + * Overloaded getter for element's attribute. + */ + final public function &__get(string $name): mixed + { + return $this->attrs[$name]; + } + + + /** + * Overloaded tester for element's attribute. + */ + final public function __isset(string $name): bool + { + return isset($this->attrs[$name]); + } + + + /** + * Overloaded unsetter for element's attribute. + */ + final public function __unset(string $name): void + { + unset($this->attrs[$name]); + } + + + /** + * Overloaded setter for element's attribute. + */ + final public function __call(string $m, array $args): mixed + { + $p = substr($m, 0, 3); + if ($p === 'get' || $p === 'set' || $p === 'add') { + $m = substr($m, 3); + $m[0] = $m[0] | "\x20"; + if ($p === 'get') { + return $this->attrs[$m] ?? null; + + } elseif ($p === 'add') { + $args[] = true; + } + } + + if (count($args) === 0) { // invalid + + } elseif (count($args) === 1) { // set + $this->attrs[$m] = $args[0]; + + } else { // add + $this->appendAttribute($m, $args[0], $args[1]); + } + + return $this; + } + + + /** + * Special setter for element's attribute. + */ + final public function href(string $path, array $query = []): static + { + if ($query) { + $query = http_build_query($query, '', '&'); + if ($query !== '') { + $path .= '?' . $query; + } + } + + $this->attrs['href'] = $path; + return $this; + } + + + /** + * Setter for data-* attributes. Booleans are converted to 'true' resp. 'false'. + */ + public function data(string $name, mixed $value = null): static + { + if (func_num_args() === 1) { + $this->attrs['data'] = $name; + } else { + $this->attrs["data-$name"] = is_bool($value) + ? json_encode($value) + : $value; + } + + return $this; + } + + + /** + * Sets element's HTML content. + */ + final public function setHtml(mixed $html): static + { + $this->children = [(string) $html]; + return $this; + } + + + /** + * Returns element's HTML content. + */ + final public function getHtml(): string + { + return implode('', $this->children); + } + + + /** + * Sets element's textual content. + */ + final public function setText(mixed $text): static + { + if (!$text instanceof HtmlStringable) { + $text = htmlspecialchars((string) $text, ENT_NOQUOTES, 'UTF-8'); + } + + $this->children = [(string) $text]; + return $this; + } + + + /** + * Returns element's textual content. + */ + final public function getText(): string + { + return self::htmlToText($this->getHtml()); + } + + + /** + * Adds new element's child. + */ + final public function addHtml(HtmlStringable|string $child): static + { + return $this->insert(null, $child); + } + + + /** + * Appends plain-text string to element content. + */ + public function addText(\Stringable|string $text): static + { + if (!$text instanceof HtmlStringable) { + $text = htmlspecialchars((string) $text, ENT_NOQUOTES, 'UTF-8'); + } + + return $this->insert(null, $text); + } + + + /** + * Creates and adds a new Html child. + */ + final public function create(string $name, array|string|null $attrs = null): static + { + $this->insert(null, $child = static::el($name, $attrs)); + return $child; + } + + + /** + * Inserts child node. + */ + public function insert(?int $index, HtmlStringable|string $child, bool $replace = false): static + { + $child = $child instanceof self ? $child : (string) $child; + if ($index === null) { // append + $this->children[] = $child; + + } else { // insert or replace + array_splice($this->children, $index, $replace ? 1 : 0, [$child]); + } + + return $this; + } + + + /** + * Inserts (replaces) child node (\ArrayAccess implementation). + * @param int|null $index position or null for appending + * @param Html|string $child Html node or raw HTML string + */ + final public function offsetSet($index, $child): void + { + $this->insert($index, $child, replace: true); + } + + + /** + * Returns child node (\ArrayAccess implementation). + * @param int $index + */ + final public function offsetGet($index): HtmlStringable|string + { + return $this->children[$index]; + } + + + /** + * Exists child node? (\ArrayAccess implementation). + * @param int $index + */ + final public function offsetExists($index): bool + { + return isset($this->children[$index]); + } + + + /** + * Removes child node (\ArrayAccess implementation). + * @param int $index + */ + public function offsetUnset($index): void + { + if (isset($this->children[$index])) { + array_splice($this->children, $index, 1); + } + } + + + /** + * Returns children count. + */ + final public function count(): int + { + return count($this->children); + } + + + /** + * Removes all children. + */ + public function removeChildren(): void + { + $this->children = []; + } + + + /** + * Iterates over elements. + * @return \ArrayIterator + */ + final public function getIterator(): \ArrayIterator + { + return new \ArrayIterator($this->children); + } + + + /** + * Returns all children. + */ + final public function getChildren(): array + { + return $this->children; + } + + + /** + * Renders element's start tag, content and end tag. + */ + final public function render(?int $indent = null): string + { + $s = $this->startTag(); + + if (!$this->isEmpty) { + // add content + if ($indent !== null) { + $indent++; + } + + foreach ($this->children as $child) { + if ($child instanceof self) { + $s .= $child->render($indent); + } else { + $s .= $child; + } + } + + // add end tag + $s .= $this->endTag(); + } + + if ($indent !== null) { + return "\n" . str_repeat("\t", $indent - 1) . $s . "\n" . str_repeat("\t", max(0, $indent - 2)); + } + + return $s; + } + + + final public function __toString(): string + { + return $this->render(); + } + + + /** + * Returns element's start tag. + */ + final public function startTag(): string + { + return $this->name + ? '<' . $this->name . $this->attributes() . '>' + : ''; + } + + + /** + * Returns element's end tag. + */ + final public function endTag(): string + { + return $this->name && !$this->isEmpty ? 'name . '>' : ''; + } + + + /** + * Returns element's attributes. + * @internal + */ + final public function attributes(): string + { + if (!is_array($this->attrs)) { + return ''; + } + + $s = ''; + $attrs = $this->attrs; + foreach ($attrs as $key => $value) { + if ($value === null || $value === false) { + continue; + + } elseif ($value === true) { + $s .= ' ' . $key; + + continue; + + } elseif (is_array($value)) { + if (strncmp($key, 'data-', 5) === 0) { + $value = Json::encode($value); + + } else { + $tmp = null; + foreach ($value as $k => $v) { + if ($v != null) { // intentionally ==, skip nulls & empty string + // composite 'style' vs. 'others' + $tmp[] = $v === true + ? $k + : (is_string($k) ? $k . ':' . $v : $v); + } + } + + if ($tmp === null) { + continue; + } + + $value = implode($key === 'style' || !strncmp($key, 'on', 2) ? ';' : ' ', $tmp); + } + } elseif (is_float($value)) { + $value = rtrim(rtrim(number_format($value, 10, '.', ''), '0'), '.'); + + } else { + $value = (string) $value; + } + + $q = str_contains($value, '"') ? "'" : '"'; + $s .= ' ' . $key . '=' . $q + . str_replace( + ['&', $q, '<'], + ['&', $q === '"' ? '"' : ''', '<'], + $value, + ) + . (str_contains($value, '`') && strpbrk($value, ' <>"\'') === false ? ' ' : '') + . $q; + } + + $s = str_replace('@', '@', $s); + return $s; + } + + + /** + * Clones all children too. + */ + public function __clone() + { + foreach ($this->children as $key => $value) { + if (is_object($value)) { + $this->children[$key] = clone $value; + } + } + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Image.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Image.php new file mode 100644 index 00000000000..a6bb4782a3d --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Image.php @@ -0,0 +1,818 @@ + + * $image = Image::fromFile('nette.jpg'); + * $image->resize(150, 100); + * $image->sharpen(); + * $image->send(); + * + * + * @method Image affine(array $affine, ?array $clip = null) + * @method void alphaBlending(bool $enable) + * @method void antialias(bool $enable) + * @method void arc(int $centerX, int $centerY, int $width, int $height, int $startAngle, int $endAngle, ImageColor $color) + * @method int colorAllocate(int $red, int $green, int $blue) + * @method int colorAllocateAlpha(int $red, int $green, int $blue, int $alpha) + * @method int colorAt(int $x, int $y) + * @method int colorClosest(int $red, int $green, int $blue) + * @method int colorClosestAlpha(int $red, int $green, int $blue, int $alpha) + * @method int colorClosestHWB(int $red, int $green, int $blue) + * @method void colorDeallocate(int $color) + * @method int colorExact(int $red, int $green, int $blue) + * @method int colorExactAlpha(int $red, int $green, int $blue, int $alpha) + * @method void colorMatch(Image $image2) + * @method int colorResolve(int $red, int $green, int $blue) + * @method int colorResolveAlpha(int $red, int $green, int $blue, int $alpha) + * @method void colorSet(int $index, int $red, int $green, int $blue, int $alpha = 0) + * @method array colorsForIndex(int $color) + * @method int colorsTotal() + * @method int colorTransparent(?int $color = null) + * @method void convolution(array $matrix, float $div, float $offset) + * @method void copy(Image $src, int $dstX, int $dstY, int $srcX, int $srcY, int $srcW, int $srcH) + * @method void copyMerge(Image $src, int $dstX, int $dstY, int $srcX, int $srcY, int $srcW, int $srcH, int $pct) + * @method void copyMergeGray(Image $src, int $dstX, int $dstY, int $srcX, int $srcY, int $srcW, int $srcH, int $pct) + * @method void copyResampled(Image $src, int $dstX, int $dstY, int $srcX, int $srcY, int $dstW, int $dstH, int $srcW, int $srcH) + * @method void copyResized(Image $src, int $dstX, int $dstY, int $srcX, int $srcY, int $dstW, int $dstH, int $srcW, int $srcH) + * @method Image cropAuto(int $mode = IMG_CROP_DEFAULT, float $threshold = .5, ?ImageColor $color = null) + * @method void ellipse(int $centerX, int $centerY, int $width, int $height, ImageColor $color) + * @method void fill(int $x, int $y, ImageColor $color) + * @method void filledArc(int $centerX, int $centerY, int $width, int $height, int $startAngle, int $endAngle, ImageColor $color, int $style) + * @method void filledEllipse(int $centerX, int $centerY, int $width, int $height, ImageColor $color) + * @method void filledPolygon(array $points, ImageColor $color) + * @method void filledRectangle(int $x1, int $y1, int $x2, int $y2, ImageColor $color) + * @method void fillToBorder(int $x, int $y, ImageColor $borderColor, ImageColor $color) + * @method void filter(int $filter, ...$args) + * @method void flip(int $mode) + * @method array ftText(float $size, float $angle, int $x, int $y, ImageColor $color, string $fontFile, string $text, array $options = []) + * @method void gammaCorrect(float $inputgamma, float $outputgamma) + * @method array getClip() + * @method int getInterpolation() + * @method int interlace(?bool $enable = null) + * @method bool isTrueColor() + * @method void layerEffect(int $effect) + * @method void line(int $x1, int $y1, int $x2, int $y2, ImageColor $color) + * @method void openPolygon(array $points, ImageColor $color) + * @method void paletteCopy(Image $source) + * @method void paletteToTrueColor() + * @method void polygon(array $points, ImageColor $color) + * @method void rectangle(int $x1, int $y1, int $x2, int $y2, ImageColor $color) + * @method mixed resolution(?int $resolutionX = null, ?int $resolutionY = null) + * @method Image rotate(float $angle, ImageColor $backgroundColor) + * @method void saveAlpha(bool $enable) + * @method Image scale(int $newWidth, int $newHeight = -1, int $mode = IMG_BILINEAR_FIXED) + * @method void setBrush(Image $brush) + * @method void setClip(int $x1, int $y1, int $x2, int $y2) + * @method void setInterpolation(int $method = IMG_BILINEAR_FIXED) + * @method void setPixel(int $x, int $y, ImageColor $color) + * @method void setStyle(array $style) + * @method void setThickness(int $thickness) + * @method void setTile(Image $tile) + * @method void trueColorToPalette(bool $dither, int $ncolors) + * @method array ttfText(float $size, float $angle, int $x, int $y, ImageColor $color, string $fontfile, string $text, array $options = []) + * @property-read positive-int $width + * @property-read positive-int $height + * @property-read \GdImage $imageResource + */ +class Image +{ + use Nette\SmartObject; + + /** Prevent from getting resized to a bigger size than the original */ + public const ShrinkOnly = 0b0001; + + /** Resizes to a specified width and height without keeping aspect ratio */ + public const Stretch = 0b0010; + + /** Resizes to fit into a specified width and height and preserves aspect ratio */ + public const OrSmaller = 0b0000; + + /** Resizes while bounding the smaller dimension to the specified width or height and preserves aspect ratio */ + public const OrBigger = 0b0100; + + /** Resizes to the smallest possible size to completely cover specified width and height and reserves aspect ratio */ + public const Cover = 0b1000; + + /** @deprecated use Image::ShrinkOnly */ + public const SHRINK_ONLY = self::ShrinkOnly; + + /** @deprecated use Image::Stretch */ + public const STRETCH = self::Stretch; + + /** @deprecated use Image::OrSmaller */ + public const FIT = self::OrSmaller; + + /** @deprecated use Image::OrBigger */ + public const FILL = self::OrBigger; + + /** @deprecated use Image::Cover */ + public const EXACT = self::Cover; + + /** @deprecated use Image::EmptyGIF */ + public const EMPTY_GIF = self::EmptyGIF; + + /** image types */ + public const + JPEG = ImageType::JPEG, + PNG = ImageType::PNG, + GIF = ImageType::GIF, + WEBP = ImageType::WEBP, + AVIF = ImageType::AVIF, + BMP = ImageType::BMP; + + public const EmptyGIF = "GIF89a\x01\x00\x01\x00\x80\x00\x00\x00\x00\x00\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;"; + + private const Formats = [ImageType::JPEG => 'jpeg', ImageType::PNG => 'png', ImageType::GIF => 'gif', ImageType::WEBP => 'webp', ImageType::AVIF => 'avif', ImageType::BMP => 'bmp']; + + private \GdImage $image; + + + /** + * Returns RGB color (0..255) and transparency (0..127). + * @deprecated use ImageColor::rgb() + */ + public static function rgb(int $red, int $green, int $blue, int $transparency = 0): array + { + return [ + 'red' => max(0, min(255, $red)), + 'green' => max(0, min(255, $green)), + 'blue' => max(0, min(255, $blue)), + 'alpha' => max(0, min(127, $transparency)), + ]; + } + + + /** + * Reads an image from a file and returns its type in $type. + * @throws Nette\NotSupportedException if gd extension is not loaded + * @throws UnknownImageFileException if file not found or file type is not known + */ + public static function fromFile(string $file, ?int &$type = null): static + { + self::ensureExtension(); + $type = self::detectTypeFromFile($file); + if (!$type) { + throw new UnknownImageFileException(is_file($file) ? "Unknown type of file '$file'." : "File '$file' not found."); + } + + return self::invokeSafe('imagecreatefrom' . self::Formats[$type], $file, "Unable to open file '$file'.", __METHOD__); + } + + + /** + * Reads an image from a string and returns its type in $type. + * @throws Nette\NotSupportedException if gd extension is not loaded + * @throws ImageException + */ + public static function fromString(string $s, ?int &$type = null): static + { + self::ensureExtension(); + $type = self::detectTypeFromString($s); + if (!$type) { + throw new UnknownImageFileException('Unknown type of image.'); + } + + return self::invokeSafe('imagecreatefromstring', $s, 'Unable to open image from string.', __METHOD__); + } + + + private static function invokeSafe(string $func, string $arg, string $message, string $callee): static + { + $errors = []; + $res = Callback::invokeSafe($func, [$arg], function (string $message) use (&$errors): void { + $errors[] = $message; + }); + + if (!$res) { + throw new ImageException($message . ' Errors: ' . implode(', ', $errors)); + } elseif ($errors) { + trigger_error($callee . '(): ' . implode(', ', $errors), E_USER_WARNING); + } + + return new static($res); + } + + + /** + * Creates a new true color image of the given dimensions. The default color is black. + * @param positive-int $width + * @param positive-int $height + * @throws Nette\NotSupportedException if gd extension is not loaded + */ + public static function fromBlank(int $width, int $height, ImageColor|array|null $color = null): static + { + self::ensureExtension(); + if ($width < 1 || $height < 1) { + throw new Nette\InvalidArgumentException('Image width and height must be greater than zero.'); + } + + $image = new static(imagecreatetruecolor($width, $height)); + if ($color) { + $image->alphablending(false); + $image->filledrectangle(0, 0, $width - 1, $height - 1, $color); + $image->alphablending(true); + } + + return $image; + } + + + /** + * Returns the type of image from file. + * @return ImageType::*|null + */ + public static function detectTypeFromFile(string $file, &$width = null, &$height = null): ?int + { + [$width, $height, $type] = Helpers::falseToNull(@getimagesize($file)); // @ - files smaller than 12 bytes causes read error + return $type && isset(self::Formats[$type]) ? $type : null; + } + + + /** + * Returns the type of image from string. + * @return ImageType::*|null + */ + public static function detectTypeFromString(string $s, &$width = null, &$height = null): ?int + { + [$width, $height, $type] = Helpers::falseToNull(@getimagesizefromstring($s)); // @ - strings smaller than 12 bytes causes read error + return $type && isset(self::Formats[$type]) ? $type : null; + } + + + /** + * Returns the file extension for the given image type. + * @param ImageType::* $type + * @return value-of + */ + public static function typeToExtension(int $type): string + { + if (!isset(self::Formats[$type])) { + throw new Nette\InvalidArgumentException("Unsupported image type '$type'."); + } + + return self::Formats[$type]; + } + + + /** + * Returns the image type for given file extension. + * @return ImageType::* + */ + public static function extensionToType(string $extension): int + { + $extensions = array_flip(self::Formats) + ['jpg' => ImageType::JPEG]; + $extension = strtolower($extension); + if (!isset($extensions[$extension])) { + throw new Nette\InvalidArgumentException("Unsupported file extension '$extension'."); + } + + return $extensions[$extension]; + } + + + /** + * Returns the mime type for the given image type. + * @param ImageType::* $type + */ + public static function typeToMimeType(int $type): string + { + return 'image/' . self::typeToExtension($type); + } + + + /** + * @param ImageType::* $type + */ + public static function isTypeSupported(int $type): bool + { + self::ensureExtension(); + return (bool) (imagetypes() & match ($type) { + ImageType::JPEG => IMG_JPG, + ImageType::PNG => IMG_PNG, + ImageType::GIF => IMG_GIF, + ImageType::WEBP => IMG_WEBP, + ImageType::AVIF => 256, // IMG_AVIF, + ImageType::BMP => IMG_BMP, + default => 0, + }); + } + + + /** @return ImageType[] */ + public static function getSupportedTypes(): array + { + self::ensureExtension(); + $flag = imagetypes(); + return array_filter([ + $flag & IMG_GIF ? ImageType::GIF : null, + $flag & IMG_JPG ? ImageType::JPEG : null, + $flag & IMG_PNG ? ImageType::PNG : null, + $flag & IMG_WEBP ? ImageType::WEBP : null, + $flag & 256 ? ImageType::AVIF : null, // IMG_AVIF + $flag & IMG_BMP ? ImageType::BMP : null, + ]); + } + + + /** + * Wraps GD image. + */ + public function __construct(\GdImage $image) + { + $this->setImageResource($image); + imagesavealpha($image, true); + } + + + /** + * Returns image width. + * @return positive-int + */ + public function getWidth(): int + { + return imagesx($this->image); + } + + + /** + * Returns image height. + * @return positive-int + */ + public function getHeight(): int + { + return imagesy($this->image); + } + + + /** + * Sets image resource. + */ + protected function setImageResource(\GdImage $image): static + { + $this->image = $image; + return $this; + } + + + /** + * Returns image GD resource. + */ + public function getImageResource(): \GdImage + { + return $this->image; + } + + + /** + * Scales an image. Width and height accept pixels or percent. + * @param int-mask-of $mode + */ + public function resize(int|string|null $width, int|string|null $height, int $mode = self::OrSmaller): static + { + if ($mode & self::Cover) { + return $this->resize($width, $height, self::OrBigger)->crop('50%', '50%', $width, $height); + } + + [$newWidth, $newHeight] = static::calculateSize($this->getWidth(), $this->getHeight(), $width, $height, $mode); + + if ($newWidth !== $this->getWidth() || $newHeight !== $this->getHeight()) { // resize + $newImage = static::fromBlank($newWidth, $newHeight, ImageColor::rgb(0, 0, 0, 0))->getImageResource(); + imagecopyresampled( + $newImage, + $this->image, + 0, + 0, + 0, + 0, + $newWidth, + $newHeight, + $this->getWidth(), + $this->getHeight(), + ); + $this->image = $newImage; + } + + if ($width < 0 || $height < 0) { + imageflip($this->image, $width < 0 ? ($height < 0 ? IMG_FLIP_BOTH : IMG_FLIP_HORIZONTAL) : IMG_FLIP_VERTICAL); + } + + return $this; + } + + + /** + * Calculates dimensions of resized image. Width and height accept pixels or percent. + * @param int-mask-of $mode + */ + public static function calculateSize( + int $srcWidth, + int $srcHeight, + $newWidth, + $newHeight, + int $mode = self::OrSmaller, + ): array + { + if ($newWidth === null) { + } elseif (self::isPercent($newWidth)) { + $newWidth = (int) round($srcWidth / 100 * abs($newWidth)); + $percents = true; + } else { + $newWidth = abs($newWidth); + } + + if ($newHeight === null) { + } elseif (self::isPercent($newHeight)) { + $newHeight = (int) round($srcHeight / 100 * abs($newHeight)); + $mode |= empty($percents) ? 0 : self::Stretch; + } else { + $newHeight = abs($newHeight); + } + + if ($mode & self::Stretch) { // non-proportional + if (!$newWidth || !$newHeight) { + throw new Nette\InvalidArgumentException('For stretching must be both width and height specified.'); + } + + if ($mode & self::ShrinkOnly) { + $newWidth = min($srcWidth, $newWidth); + $newHeight = min($srcHeight, $newHeight); + } + } else { // proportional + if (!$newWidth && !$newHeight) { + throw new Nette\InvalidArgumentException('At least width or height must be specified.'); + } + + $scale = []; + if ($newWidth > 0) { // fit width + $scale[] = $newWidth / $srcWidth; + } + + if ($newHeight > 0) { // fit height + $scale[] = $newHeight / $srcHeight; + } + + if ($mode & self::OrBigger) { + $scale = [max($scale)]; + } + + if ($mode & self::ShrinkOnly) { + $scale[] = 1; + } + + $scale = min($scale); + $newWidth = (int) round($srcWidth * $scale); + $newHeight = (int) round($srcHeight * $scale); + } + + return [max($newWidth, 1), max($newHeight, 1)]; + } + + + /** + * Crops image. Arguments accepts pixels or percent. + */ + public function crop(int|string $left, int|string $top, int|string $width, int|string $height): static + { + [$r['x'], $r['y'], $r['width'], $r['height']] + = static::calculateCutout($this->getWidth(), $this->getHeight(), $left, $top, $width, $height); + if (gd_info()['GD Version'] === 'bundled (2.1.0 compatible)') { + $this->image = imagecrop($this->image, $r); + imagesavealpha($this->image, true); + } else { + $newImage = static::fromBlank($r['width'], $r['height'], ImageColor::rgb(0, 0, 0, 0))->getImageResource(); + imagecopy($newImage, $this->image, 0, 0, $r['x'], $r['y'], $r['width'], $r['height']); + $this->image = $newImage; + } + + return $this; + } + + + /** + * Calculates dimensions of cutout in image. Arguments accepts pixels or percent. + */ + public static function calculateCutout( + int $srcWidth, + int $srcHeight, + int|string $left, + int|string $top, + int|string $newWidth, + int|string $newHeight, + ): array + { + if (self::isPercent($newWidth)) { + $newWidth = (int) round($srcWidth / 100 * $newWidth); + } + + if (self::isPercent($newHeight)) { + $newHeight = (int) round($srcHeight / 100 * $newHeight); + } + + if (self::isPercent($left)) { + $left = (int) round(($srcWidth - $newWidth) / 100 * $left); + } + + if (self::isPercent($top)) { + $top = (int) round(($srcHeight - $newHeight) / 100 * $top); + } + + if ($left < 0) { + $newWidth += $left; + $left = 0; + } + + if ($top < 0) { + $newHeight += $top; + $top = 0; + } + + $newWidth = min($newWidth, $srcWidth - $left); + $newHeight = min($newHeight, $srcHeight - $top); + return [$left, $top, $newWidth, $newHeight]; + } + + + /** + * Sharpens image a little bit. + */ + public function sharpen(): static + { + imageconvolution($this->image, [ // my magic numbers ;) + [-1, -1, -1], + [-1, 24, -1], + [-1, -1, -1], + ], 16, 0); + return $this; + } + + + /** + * Puts another image into this image. Left and top accepts pixels or percent. + * @param int<0, 100> $opacity 0..100 + */ + public function place(self $image, int|string $left = 0, int|string $top = 0, int $opacity = 100): static + { + $opacity = max(0, min(100, $opacity)); + if ($opacity === 0) { + return $this; + } + + $width = $image->getWidth(); + $height = $image->getHeight(); + + if (self::isPercent($left)) { + $left = (int) round(($this->getWidth() - $width) / 100 * $left); + } + + if (self::isPercent($top)) { + $top = (int) round(($this->getHeight() - $height) / 100 * $top); + } + + $output = $input = $image->image; + if ($opacity < 100) { + $tbl = []; + for ($i = 0; $i < 128; $i++) { + $tbl[$i] = round(127 - (127 - $i) * $opacity / 100); + } + + $output = imagecreatetruecolor($width, $height); + imagealphablending($output, false); + if (!$image->isTrueColor()) { + $input = $output; + imagefilledrectangle($output, 0, 0, $width, $height, imagecolorallocatealpha($output, 0, 0, 0, 127)); + imagecopy($output, $image->image, 0, 0, 0, 0, $width, $height); + } + + for ($x = 0; $x < $width; $x++) { + for ($y = 0; $y < $height; $y++) { + $c = \imagecolorat($input, $x, $y); + $c = ($c & 0xFFFFFF) + ($tbl[$c >> 24] << 24); + \imagesetpixel($output, $x, $y, $c); + } + } + + imagealphablending($output, true); + } + + imagecopy( + $this->image, + $output, + $left, + $top, + 0, + 0, + $width, + $height, + ); + return $this; + } + + + /** + * Calculates the bounding box for a TrueType text. Returns keys left, top, width and height. + */ + public static function calculateTextBox( + string $text, + string $fontFile, + float $size, + float $angle = 0, + array $options = [], + ): array + { + self::ensureExtension(); + $box = imagettfbbox($size, $angle, $fontFile, $text, $options); + return [ + 'left' => $minX = min([$box[0], $box[2], $box[4], $box[6]]), + 'top' => $minY = min([$box[1], $box[3], $box[5], $box[7]]), + 'width' => max([$box[0], $box[2], $box[4], $box[6]]) - $minX + 1, + 'height' => max([$box[1], $box[3], $box[5], $box[7]]) - $minY + 1, + ]; + } + + + /** + * Draw a rectangle. + */ + public function rectangleWH(int $x, int $y, int $width, int $height, ImageColor $color): void + { + if ($width !== 0 && $height !== 0) { + $this->rectangle($x, $y, $x + $width + ($width > 0 ? -1 : 1), $y + $height + ($height > 0 ? -1 : 1), $color); + } + } + + + /** + * Draw a filled rectangle. + */ + public function filledRectangleWH(int $x, int $y, int $width, int $height, ImageColor $color): void + { + if ($width !== 0 && $height !== 0) { + $this->filledRectangle($x, $y, $x + $width + ($width > 0 ? -1 : 1), $y + $height + ($height > 0 ? -1 : 1), $color); + } + } + + + /** + * Saves image to the file. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + * @param ImageType::*|null $type + * @throws ImageException + */ + public function save(string $file, ?int $quality = null, ?int $type = null): void + { + $type ??= self::extensionToType(pathinfo($file, PATHINFO_EXTENSION)); + $this->output($type, $quality, $file); + } + + + /** + * Outputs image to string. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + * @param ImageType::* $type + */ + public function toString(int $type = ImageType::JPEG, ?int $quality = null): string + { + return Helpers::capture(function () use ($type, $quality): void { + $this->output($type, $quality); + }); + } + + + /** + * Outputs image to string. + */ + public function __toString(): string + { + return $this->toString(); + } + + + /** + * Outputs image to browser. Quality is in the range 0..100 for JPEG (default 85), WEBP (default 80) and AVIF (default 30) and 0..9 for PNG (default 9). + * @param ImageType::* $type + * @throws ImageException + */ + public function send(int $type = ImageType::JPEG, ?int $quality = null): void + { + header('Content-Type: ' . self::typeToMimeType($type)); + $this->output($type, $quality); + } + + + /** + * Outputs image to browser or file. + * @param ImageType::* $type + * @throws ImageException + */ + private function output(int $type, ?int $quality, ?string $file = null): void + { + [$defQuality, $min, $max] = match ($type) { + ImageType::JPEG => [85, 0, 100], + ImageType::PNG => [9, 0, 9], + ImageType::GIF => [null, null, null], + ImageType::WEBP => [80, 0, 100], + ImageType::AVIF => [30, 0, 100], + ImageType::BMP => [null, null, null], + default => throw new Nette\InvalidArgumentException("Unsupported image type '$type'."), + }; + + $args = [$this->image, $file]; + if ($defQuality !== null) { + $args[] = $quality === null ? $defQuality : max($min, min($max, $quality)); + } + + Callback::invokeSafe('image' . self::Formats[$type], $args, function (string $message) use ($file): void { + if ($file !== null) { + @unlink($file); + } + throw new ImageException($message); + }); + } + + + /** + * Call to undefined method. + * @throws Nette\MemberAccessException + */ + public function __call(string $name, array $args): mixed + { + $function = 'image' . $name; + if (!function_exists($function)) { + ObjectHelpers::strictCall(static::class, $name); + } + + foreach ($args as $key => $value) { + if ($value instanceof self) { + $args[$key] = $value->getImageResource(); + + } elseif ($value instanceof ImageColor || (is_array($value) && isset($value['red']))) { + $args[$key] = $this->resolveColor($value); + } + } + + $res = $function($this->image, ...$args); + return $res instanceof \GdImage + ? $this->setImageResource($res) + : $res; + } + + + public function __clone() + { + ob_start(fn() => ''); + imagepng($this->image, null, 0); + $this->setImageResource(imagecreatefromstring(ob_get_clean())); + } + + + private static function isPercent(int|string &$num): bool + { + if (is_string($num) && str_ends_with($num, '%')) { + $num = (float) substr($num, 0, -1); + return true; + } elseif (is_int($num) || $num === (string) (int) $num) { + $num = (int) $num; + return false; + } + + throw new Nette\InvalidArgumentException("Expected dimension in int|string, '$num' given."); + } + + + /** + * Prevents serialization. + */ + public function __serialize(): array + { + throw new Nette\NotSupportedException('You cannot serialize or unserialize ' . self::class . ' instances.'); + } + + + public function resolveColor(ImageColor|array $color): int + { + $color = $color instanceof ImageColor ? $color->toRGBA() : array_values($color); + return imagecolorallocatealpha($this->image, ...$color) ?: imagecolorresolvealpha($this->image, ...$color); + } + + + private static function ensureExtension(): void + { + if (!extension_loaded('gd')) { + throw new Nette\NotSupportedException('PHP extension GD is not loaded.'); + } + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/ImageColor.php b/tools/.phpstan/vendor/nette/utils/src/Utils/ImageColor.php new file mode 100644 index 00000000000..66966620dd9 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/ImageColor.php @@ -0,0 +1,76 @@ +red = max(0, min(255, $red)); + $this->green = max(0, min(255, $green)); + $this->blue = max(0, min(255, $blue)); + $this->opacity = max(0, min(1, $opacity)); + } + + + public function toRGBA(): array + { + return [ + max(0, min(255, $this->red)), + max(0, min(255, $this->green)), + max(0, min(255, $this->blue)), + max(0, min(127, (int) round(127 - $this->opacity * 127))), + ]; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/ImageType.php b/tools/.phpstan/vendor/nette/utils/src/Utils/ImageType.php new file mode 100644 index 00000000000..080ca8a09e2 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/ImageType.php @@ -0,0 +1,27 @@ + $v) { + if ($k === $key) { + return true; + } + } + return false; + } + + + /** + * Returns the first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null. + * @template K + * @template V + * @param iterable $iterable + * @param ?callable(V, K, iterable): bool $predicate + * @return ?V + */ + public static function first(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed + { + foreach ($iterable as $k => $v) { + if (!$predicate || $predicate($v, $k, $iterable)) { + return $v; + } + } + return $else ? $else() : null; + } + + + /** + * Returns the key of first item (matching the specified predicate if given). If there is no such item, it returns result of invoking $else or null. + * @template K + * @template V + * @param iterable $iterable + * @param ?callable(V, K, iterable): bool $predicate + * @return ?K + */ + public static function firstKey(iterable $iterable, ?callable $predicate = null, ?callable $else = null): mixed + { + foreach ($iterable as $k => $v) { + if (!$predicate || $predicate($v, $k, $iterable)) { + return $k; + } + } + return $else ? $else() : null; + } + + + /** + * Tests whether at least one element in the iterator passes the test implemented by the provided function. + * @template K + * @template V + * @param iterable $iterable + * @param callable(V, K, iterable): bool $predicate + */ + public static function some(iterable $iterable, callable $predicate): bool + { + foreach ($iterable as $k => $v) { + if ($predicate($v, $k, $iterable)) { + return true; + } + } + return false; + } + + + /** + * Tests whether all elements in the iterator pass the test implemented by the provided function. + * @template K + * @template V + * @param iterable $iterable + * @param callable(V, K, iterable): bool $predicate + */ + public static function every(iterable $iterable, callable $predicate): bool + { + foreach ($iterable as $k => $v) { + if (!$predicate($v, $k, $iterable)) { + return false; + } + } + return true; + } + + + /** + * Iterator that filters elements according to a given $predicate. Maintains original keys. + * @template K + * @template V + * @param iterable $iterable + * @param callable(V, K, iterable): bool $predicate + * @return \Generator + */ + public static function filter(iterable $iterable, callable $predicate): \Generator + { + foreach ($iterable as $k => $v) { + if ($predicate($v, $k, $iterable)) { + yield $k => $v; + } + } + } + + + /** + * Iterator that transforms values by calling $transformer. Maintains original keys. + * @template K + * @template V + * @template R + * @param iterable $iterable + * @param callable(V, K, iterable): R $transformer + * @return \Generator + */ + public static function map(iterable $iterable, callable $transformer): \Generator + { + foreach ($iterable as $k => $v) { + yield $k => $transformer($v, $k, $iterable); + } + } + + + /** + * Iterator that transforms keys and values by calling $transformer. If it returns null, the element is skipped. + * @template K + * @template V + * @template ResV + * @template ResK + * @param iterable $iterable + * @param callable(V, K, iterable): ?array{ResV, ResK} $transformer + * @return \Generator + */ + public static function mapWithKeys(iterable $iterable, callable $transformer): \Generator + { + foreach ($iterable as $k => $v) { + $pair = $transformer($v, $k, $iterable); + if ($pair) { + yield $pair[0] => $pair[1]; + } + } + } + + + /** + * Creates a repeatable iterator from a factory function. + * The factory is called every time the iterator is iterated. + * @template K + * @template V + * @param callable(): iterable $factory + * @return \IteratorAggregate + */ + public static function repeatable(callable $factory): \IteratorAggregate + { + return new class ($factory) implements \IteratorAggregate { + public function __construct( + private $factory, + ) { + } + + + public function getIterator(): \Iterator + { + return Iterables::toIterator(($this->factory)()); + } + }; + } + + + /** + * Wraps around iterator and caches its keys and values during iteration. + * This allows the data to be re-iterated multiple times. + * @template K + * @template V + * @param iterable $iterable + * @return \IteratorAggregate + */ + public static function memoize(iterable $iterable): \IteratorAggregate + { + return new class (self::toIterator($iterable)) implements \IteratorAggregate { + public function __construct( + private \Iterator $iterator, + private array $cache = [], + ) { + } + + + public function getIterator(): \Generator + { + if (!$this->cache) { + $this->iterator->rewind(); + } + $i = 0; + while (true) { + if (isset($this->cache[$i])) { + [$k, $v] = $this->cache[$i]; + } elseif ($this->iterator->valid()) { + $k = $this->iterator->key(); + $v = $this->iterator->current(); + $this->iterator->next(); + $this->cache[$i] = [$k, $v]; + } else { + break; + } + yield $k => $v; + $i++; + } + } + }; + } + + + /** + * Creates an iterator from anything that is iterable. + * @template K + * @template V + * @param iterable $iterable + * @return \Iterator + */ + public static function toIterator(iterable $iterable): \Iterator + { + return match (true) { + $iterable instanceof \Iterator => $iterable, + $iterable instanceof \IteratorAggregate => self::toIterator($iterable->getIterator()), + is_array($iterable) => new \ArrayIterator($iterable), + default => throw new Nette\ShouldNotHappenException, + }; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Json.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Json.php new file mode 100644 index 00000000000..4e4cf238eed --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Json.php @@ -0,0 +1,86 @@ +getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()), + self::parseFullDoc($rc, '~^[ \t*]*@property(?:-read)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'), + ), $name); + throw new MemberAccessException("Cannot read an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } + + + /** + * @return never + * @throws MemberAccessException + */ + public static function strictSet(string $class, string $name): void + { + $rc = new \ReflectionClass($class); + $hint = self::getSuggestion(array_merge( + array_filter($rc->getProperties(\ReflectionProperty::IS_PUBLIC), fn($p) => !$p->isStatic()), + self::parseFullDoc($rc, '~^[ \t*]*@property(?:-write)?[ \t]+(?:\S+[ \t]+)??\$(\w+)~m'), + ), $name); + throw new MemberAccessException("Cannot write to an undeclared property $class::\$$name" . ($hint ? ", did you mean \$$hint?" : '.')); + } + + + /** + * @return never + * @throws MemberAccessException + */ + public static function strictCall(string $class, string $method, array $additionalMethods = []): void + { + $trace = debug_backtrace(0, 3); // suppose this method is called from __call() + $context = ($trace[1]['function'] ?? null) === '__call' + ? ($trace[2]['class'] ?? null) + : null; + + if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method() + $class = get_parent_class($context); + } + + if (method_exists($class, $method)) { // insufficient visibility + $rm = new \ReflectionMethod($class, $method); + $visibility = $rm->isPrivate() + ? 'private ' + : ($rm->isProtected() ? 'protected ' : ''); + throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.')); + + } else { + $hint = self::getSuggestion(array_merge( + get_class_methods($class), + self::parseFullDoc(new \ReflectionClass($class), '~^[ \t*]*@method[ \t]+(?:static[ \t]+)?(?:\S+[ \t]+)??(\w+)\(~m'), + $additionalMethods, + ), $method); + throw new MemberAccessException("Call to undefined method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.')); + } + } + + + /** + * @return never + * @throws MemberAccessException + */ + public static function strictStaticCall(string $class, string $method): void + { + $trace = debug_backtrace(0, 3); // suppose this method is called from __callStatic() + $context = ($trace[1]['function'] ?? null) === '__callStatic' + ? ($trace[2]['class'] ?? null) + : null; + + if ($context && is_a($class, $context, true) && method_exists($context, $method)) { // called parent::$method() + $class = get_parent_class($context); + } + + if (method_exists($class, $method)) { // insufficient visibility + $rm = new \ReflectionMethod($class, $method); + $visibility = $rm->isPrivate() + ? 'private ' + : ($rm->isProtected() ? 'protected ' : ''); + throw new MemberAccessException("Call to {$visibility}method $class::$method() from " . ($context ? "scope $context." : 'global scope.')); + + } else { + $hint = self::getSuggestion( + array_filter((new \ReflectionClass($class))->getMethods(\ReflectionMethod::IS_PUBLIC), fn($m) => $m->isStatic()), + $method, + ); + throw new MemberAccessException("Call to undefined static method $class::$method()" . ($hint ? ", did you mean $hint()?" : '.')); + } + } + + + /** + * Returns array of magic properties defined by annotation @property. + * @return array of [name => bit mask] + * @internal + */ + public static function getMagicProperties(string $class): array + { + static $cache; + $props = &$cache[$class]; + if ($props !== null) { + return $props; + } + + $rc = new \ReflectionClass($class); + preg_match_all( + '~^ [ \t*]* @property(|-read|-write|-deprecated) [ \t]+ [^\s$]+ [ \t]+ \$ (\w+) ()~mx', + (string) $rc->getDocComment(), + $matches, + PREG_SET_ORDER, + ); + + $props = []; + foreach ($matches as [, $type, $name]) { + $uname = ucfirst($name); + $write = $type !== '-read' + && $rc->hasMethod($nm = 'set' . $uname) + && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic(); + $read = $type !== '-write' + && ($rc->hasMethod($nm = 'get' . $uname) || $rc->hasMethod($nm = 'is' . $uname)) + && ($rm = $rc->getMethod($nm))->name === $nm && !$rm->isPrivate() && !$rm->isStatic(); + + if ($read || $write) { + $props[$name] = $read << 0 | ($nm[0] === 'g') << 1 | $rm->returnsReference() << 2 | $write << 3 | ($type === '-deprecated') << 4; + } + } + + foreach ($rc->getTraits() as $trait) { + $props += self::getMagicProperties($trait->name); + } + + if ($parent = get_parent_class($class)) { + $props += self::getMagicProperties($parent); + } + + return $props; + } + + + /** + * Finds the best suggestion (for 8-bit encoding). + * @param (\ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionClass|\ReflectionProperty|string)[] $possibilities + * @internal + */ + public static function getSuggestion(array $possibilities, string $value): ?string + { + $norm = preg_replace($re = '#^(get|set|has|is|add)(?=[A-Z])#', '+', $value); + $best = null; + $min = (strlen($value) / 4 + 1) * 10 + .1; + foreach (array_unique($possibilities, SORT_REGULAR) as $item) { + $item = $item instanceof \Reflector ? $item->name : $item; + if ($item !== $value && ( + ($len = levenshtein($item, $value, 10, 11, 10)) < $min + || ($len = levenshtein(preg_replace($re, '*', $item), $norm, 10, 11, 10)) < $min + )) { + $min = $len; + $best = $item; + } + } + + return $best; + } + + + private static function parseFullDoc(\ReflectionClass $rc, string $pattern): array + { + do { + $doc[] = $rc->getDocComment(); + $traits = $rc->getTraits(); + while ($trait = array_pop($traits)) { + $doc[] = $trait->getDocComment(); + $traits += $trait->getTraits(); + } + } while ($rc = $rc->getParentClass()); + + return preg_match_all($pattern, implode('', $doc), $m) ? $m[1] : []; + } + + + /** + * Checks if the public non-static property exists. + * Returns 'event' if the property exists and has event like name + * @internal + */ + public static function hasProperty(string $class, string $name): bool|string + { + static $cache; + $prop = &$cache[$class][$name]; + if ($prop === null) { + $prop = false; + try { + $rp = new \ReflectionProperty($class, $name); + if ($rp->isPublic() && !$rp->isStatic()) { + $prop = $name >= 'onA' && $name < 'on_' ? 'event' : true; + } + } catch (\ReflectionException $e) { + } + } + + return $prop; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Paginator.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Paginator.php new file mode 100644 index 00000000000..aa4812c0a3a --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Paginator.php @@ -0,0 +1,245 @@ + $firstItemOnPage + * @property-read int<0,max> $lastItemOnPage + * @property int $base + * @property-read bool $first + * @property-read bool $last + * @property-read int<0,max>|null $pageCount + * @property positive-int $itemsPerPage + * @property int<0,max>|null $itemCount + * @property-read int<0,max> $offset + * @property-read int<0,max>|null $countdownOffset + * @property-read int<0,max> $length + */ +class Paginator +{ + use Nette\SmartObject; + + private int $base = 1; + + /** @var positive-int */ + private int $itemsPerPage = 1; + + private int $page = 1; + + /** @var int<0, max>|null */ + private ?int $itemCount = null; + + + /** + * Sets current page number. + */ + public function setPage(int $page): static + { + $this->page = $page; + return $this; + } + + + /** + * Returns current page number. + */ + public function getPage(): int + { + return $this->base + $this->getPageIndex(); + } + + + /** + * Returns first page number. + */ + public function getFirstPage(): int + { + return $this->base; + } + + + /** + * Returns last page number. + */ + public function getLastPage(): ?int + { + return $this->itemCount === null + ? null + : $this->base + max(0, $this->getPageCount() - 1); + } + + + /** + * Returns the sequence number of the first element on the page + * @return int<0, max> + */ + public function getFirstItemOnPage(): int + { + return $this->itemCount !== 0 + ? $this->offset + 1 + : 0; + } + + + /** + * Returns the sequence number of the last element on the page + * @return int<0, max> + */ + public function getLastItemOnPage(): int + { + return $this->offset + $this->length; + } + + + /** + * Sets first page (base) number. + */ + public function setBase(int $base): static + { + $this->base = $base; + return $this; + } + + + /** + * Returns first page (base) number. + */ + public function getBase(): int + { + return $this->base; + } + + + /** + * Returns zero-based page number. + * @return int<0, max> + */ + protected function getPageIndex(): int + { + $index = max(0, $this->page - $this->base); + return $this->itemCount === null + ? $index + : min($index, max(0, $this->getPageCount() - 1)); + } + + + /** + * Is the current page the first one? + */ + public function isFirst(): bool + { + return $this->getPageIndex() === 0; + } + + + /** + * Is the current page the last one? + */ + public function isLast(): bool + { + return $this->itemCount === null + ? false + : $this->getPageIndex() >= $this->getPageCount() - 1; + } + + + /** + * Returns the total number of pages. + * @return int<0, max>|null + */ + public function getPageCount(): ?int + { + return $this->itemCount === null + ? null + : (int) ceil($this->itemCount / $this->itemsPerPage); + } + + + /** + * Sets the number of items to display on a single page. + */ + public function setItemsPerPage(int $itemsPerPage): static + { + $this->itemsPerPage = max(1, $itemsPerPage); + return $this; + } + + + /** + * Returns the number of items to display on a single page. + * @return positive-int + */ + public function getItemsPerPage(): int + { + return $this->itemsPerPage; + } + + + /** + * Sets the total number of items. + */ + public function setItemCount(?int $itemCount = null): static + { + $this->itemCount = $itemCount === null ? null : max(0, $itemCount); + return $this; + } + + + /** + * Returns the total number of items. + * @return int<0, max>|null + */ + public function getItemCount(): ?int + { + return $this->itemCount; + } + + + /** + * Returns the absolute index of the first item on current page. + * @return int<0, max> + */ + public function getOffset(): int + { + return $this->getPageIndex() * $this->itemsPerPage; + } + + + /** + * Returns the absolute index of the first item on current page in countdown paging. + * @return int<0, max>|null + */ + public function getCountdownOffset(): ?int + { + return $this->itemCount === null + ? null + : max(0, $this->itemCount - ($this->getPageIndex() + 1) * $this->itemsPerPage); + } + + + /** + * Returns the number of items on current page. + * @return int<0, max> + */ + public function getLength(): int + { + return $this->itemCount === null + ? $this->itemsPerPage + : min($this->itemsPerPage, $this->itemCount - $this->getPageIndex() * $this->itemsPerPage); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Random.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Random.php new file mode 100644 index 00000000000..e636dd07207 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Random.php @@ -0,0 +1,54 @@ + implode('', range($m[0][0], $m[0][2])), + $charlist, + ); + $charlist = count_chars($charlist, mode: 3); + $chLen = strlen($charlist); + + if ($length < 1) { + throw new Nette\InvalidArgumentException('Length must be greater than zero.'); + } elseif ($chLen < 2) { + throw new Nette\InvalidArgumentException('Character list must contain at least two chars.'); + } elseif (PHP_VERSION_ID >= 80300) { + return (new Randomizer)->getBytesFromString($charlist, $length); + } + + $res = ''; + for ($i = 0; $i < $length; $i++) { + $res .= $charlist[random_int(0, $chLen - 1)]; + } + + return $res; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Reflection.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Reflection.php new file mode 100644 index 00000000000..0220984229a --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Reflection.php @@ -0,0 +1,319 @@ +isDefaultValueConstant()) { + $const = $orig = $param->getDefaultValueConstantName(); + $pair = explode('::', $const); + if (isset($pair[1])) { + $pair[0] = Type::resolve($pair[0], $param); + try { + $rcc = new \ReflectionClassConstant($pair[0], $pair[1]); + } catch (\ReflectionException $e) { + $name = self::toString($param); + throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name.", 0, $e); + } + + return $rcc->getValue(); + + } elseif (!defined($const)) { + $const = substr((string) strrchr($const, '\\'), 1); + if (!defined($const)) { + $name = self::toString($param); + throw new \ReflectionException("Unable to resolve constant $orig used as default value of $name."); + } + } + + return constant($const); + } + + return $param->getDefaultValue(); + } + + + /** + * Returns a reflection of a class or trait that contains a declaration of given property. Property can also be declared in the trait. + */ + public static function getPropertyDeclaringClass(\ReflectionProperty $prop): \ReflectionClass + { + foreach ($prop->getDeclaringClass()->getTraits() as $trait) { + if ($trait->hasProperty($prop->name) + // doc-comment guessing as workaround for insufficient PHP reflection + && $trait->getProperty($prop->name)->getDocComment() === $prop->getDocComment() + ) { + return self::getPropertyDeclaringClass($trait->getProperty($prop->name)); + } + } + + return $prop->getDeclaringClass(); + } + + + /** + * Returns a reflection of a method that contains a declaration of $method. + * Usually, each method is its own declaration, but the body of the method can also be in the trait and under a different name. + */ + public static function getMethodDeclaringMethod(\ReflectionMethod $method): \ReflectionMethod + { + // file & line guessing as workaround for insufficient PHP reflection + $decl = $method->getDeclaringClass(); + if ($decl->getFileName() === $method->getFileName() + && $decl->getStartLine() <= $method->getStartLine() + && $decl->getEndLine() >= $method->getEndLine() + ) { + return $method; + } + + $hash = [$method->getFileName(), $method->getStartLine(), $method->getEndLine()]; + if (($alias = $decl->getTraitAliases()[$method->name] ?? null) + && ($m = new \ReflectionMethod(...explode('::', $alias, 2))) + && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()] + ) { + return self::getMethodDeclaringMethod($m); + } + + foreach ($decl->getTraits() as $trait) { + if ($trait->hasMethod($method->name) + && ($m = $trait->getMethod($method->name)) + && $hash === [$m->getFileName(), $m->getStartLine(), $m->getEndLine()] + ) { + return self::getMethodDeclaringMethod($m); + } + } + + return $method; + } + + + /** + * Finds out if reflection has access to PHPdoc comments. Comments may not be available due to the opcode cache. + */ + public static function areCommentsAvailable(): bool + { + static $res; + return $res ?? $res = (bool) (new \ReflectionMethod(self::class, __FUNCTION__))->getDocComment(); + } + + + public static function toString(\Reflector $ref): string + { + if ($ref instanceof \ReflectionClass) { + return $ref->name; + } elseif ($ref instanceof \ReflectionMethod) { + return $ref->getDeclaringClass()->name . '::' . $ref->name . '()'; + } elseif ($ref instanceof \ReflectionFunction) { + return $ref->isAnonymous() ? '{closure}()' : $ref->name . '()'; + } elseif ($ref instanceof \ReflectionProperty) { + return self::getPropertyDeclaringClass($ref)->name . '::$' . $ref->name; + } elseif ($ref instanceof \ReflectionParameter) { + return '$' . $ref->name . ' in ' . self::toString($ref->getDeclaringFunction()); + } else { + throw new Nette\InvalidArgumentException; + } + } + + + /** + * Expands the name of the class to full name in the given context of given class. + * Thus, it returns how the PHP parser would understand $name if it were written in the body of the class $context. + * @throws Nette\InvalidArgumentException + */ + public static function expandClassName(string $name, \ReflectionClass $context): string + { + $lower = strtolower($name); + if (empty($name)) { + throw new Nette\InvalidArgumentException('Class name must not be empty.'); + + } elseif (Validators::isBuiltinType($lower)) { + return $lower; + + } elseif ($lower === 'self' || $lower === 'static') { + return $context->name; + + } elseif ($lower === 'parent') { + return $context->getParentClass() + ? $context->getParentClass()->name + : 'parent'; + + } elseif ($name[0] === '\\') { // fully qualified name + return ltrim($name, '\\'); + } + + $uses = self::getUseStatements($context); + $parts = explode('\\', $name, 2); + if (isset($uses[$parts[0]])) { + $parts[0] = $uses[$parts[0]]; + return implode('\\', $parts); + + } elseif ($context->inNamespace()) { + return $context->getNamespaceName() . '\\' . $name; + + } else { + return $name; + } + } + + + /** @return array of [alias => class] */ + public static function getUseStatements(\ReflectionClass $class): array + { + if ($class->isAnonymous()) { + throw new Nette\NotImplementedException('Anonymous classes are not supported.'); + } + + static $cache = []; + if (!isset($cache[$name = $class->name])) { + if ($class->isInternal()) { + $cache[$name] = []; + } else { + $code = file_get_contents($class->getFileName()); + $cache = self::parseUseStatements($code, $name) + $cache; + } + } + + return $cache[$name]; + } + + + /** + * Parses PHP code to [class => [alias => class, ...]] + */ + private static function parseUseStatements(string $code, ?string $forClass = null): array + { + try { + $tokens = \PhpToken::tokenize($code, TOKEN_PARSE); + } catch (\ParseError $e) { + trigger_error($e->getMessage(), E_USER_NOTICE); + $tokens = []; + } + + $namespace = $class = null; + $classLevel = $level = 0; + $res = $uses = []; + + $nameTokens = [T_STRING, T_NS_SEPARATOR, T_NAME_QUALIFIED, T_NAME_FULLY_QUALIFIED]; + + while ($token = current($tokens)) { + next($tokens); + switch ($token->id) { + case T_NAMESPACE: + $namespace = ltrim(self::fetch($tokens, $nameTokens) . '\\', '\\'); + $uses = []; + break; + + case T_CLASS: + case T_INTERFACE: + case T_TRAIT: + case T_ENUM: + if ($name = self::fetch($tokens, T_STRING)) { + $class = $namespace . $name; + $classLevel = $level + 1; + $res[$class] = $uses; + if ($class === $forClass) { + return $res; + } + } + + break; + + case T_USE: + while (!$class && ($name = self::fetch($tokens, $nameTokens))) { + $name = ltrim($name, '\\'); + if (self::fetch($tokens, '{')) { + while ($suffix = self::fetch($tokens, $nameTokens)) { + if (self::fetch($tokens, T_AS)) { + $uses[self::fetch($tokens, T_STRING)] = $name . $suffix; + } else { + $tmp = explode('\\', $suffix); + $uses[end($tmp)] = $name . $suffix; + } + + if (!self::fetch($tokens, ',')) { + break; + } + } + } elseif (self::fetch($tokens, T_AS)) { + $uses[self::fetch($tokens, T_STRING)] = $name; + + } else { + $tmp = explode('\\', $name); + $uses[end($tmp)] = $name; + } + + if (!self::fetch($tokens, ',')) { + break; + } + } + + break; + + case T_CURLY_OPEN: + case T_DOLLAR_OPEN_CURLY_BRACES: + case ord('{'): + $level++; + break; + + case ord('}'): + if ($level === $classLevel) { + $class = $classLevel = 0; + } + + $level--; + } + } + + return $res; + } + + + private static function fetch(array &$tokens, string|int|array $take): ?string + { + $res = null; + while ($token = current($tokens)) { + if ($token->is($take)) { + $res .= $token->text; + } elseif (!$token->is([T_DOC_COMMENT, T_WHITESPACE, T_COMMENT])) { + break; + } + + next($tokens); + } + + return $res; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/ReflectionMethod.php b/tools/.phpstan/vendor/nette/utils/src/Utils/ReflectionMethod.php new file mode 100644 index 00000000000..2a8a55c6219 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/ReflectionMethod.php @@ -0,0 +1,38 @@ +originalClass = new \ReflectionClass($objectOrMethod); + } + + + public function getOriginalClass(): \ReflectionClass + { + return $this->originalClass; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Strings.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Strings.php new file mode 100644 index 00000000000..eb44b481d01 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Strings.php @@ -0,0 +1,699 @@ += 0xD800 && $code <= 0xDFFF) || $code > 0x10FFFF) { + throw new Nette\InvalidArgumentException('Code point must be in range 0x0 to 0xD7FF or 0xE000 to 0x10FFFF.'); + } elseif (!extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.'); + } + + return iconv('UTF-32BE', 'UTF-8//IGNORE', pack('N', $code)); + } + + + /** + * Returns a code point of specific character in UTF-8 (number in range 0x0000..D7FF or 0xE000..10FFFF). + */ + public static function ord(string $c): int + { + if (!extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.'); + } + + $tmp = iconv('UTF-8', 'UTF-32BE//IGNORE', $c); + if (!$tmp) { + throw new Nette\InvalidArgumentException('Invalid UTF-8 character "' . ($c === '' ? '' : '\x' . strtoupper(bin2hex($c))) . '".'); + } + + return unpack('N', $tmp)[1]; + } + + + /** + * @deprecated use str_starts_with() + */ + public static function startsWith(string $haystack, string $needle): bool + { + return str_starts_with($haystack, $needle); + } + + + /** + * @deprecated use str_ends_with() + */ + public static function endsWith(string $haystack, string $needle): bool + { + return str_ends_with($haystack, $needle); + } + + + /** + * @deprecated use str_contains() + */ + public static function contains(string $haystack, string $needle): bool + { + return str_contains($haystack, $needle); + } + + + /** + * Returns a part of UTF-8 string specified by starting position and length. If start is negative, + * the returned string will start at the start'th character from the end of string. + */ + public static function substring(string $s, int $start, ?int $length = null): string + { + if (function_exists('mb_substr')) { + return mb_substr($s, $start, $length, 'UTF-8'); // MB is much faster + } elseif (!extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires extension ICONV or MBSTRING, neither is loaded.'); + } elseif ($length === null) { + $length = self::length($s); + } elseif ($start < 0 && $length < 0) { + $start += self::length($s); // unifies iconv_substr behavior with mb_substr + } + + return iconv_substr($s, $start, $length, 'UTF-8'); + } + + + /** + * Removes control characters, normalizes line breaks to `\n`, removes leading and trailing blank lines, + * trims end spaces on lines, normalizes UTF-8 to the normal form of NFC. + */ + public static function normalize(string $s): string + { + // convert to compressed normal form (NFC) + if (class_exists('Normalizer', false) && ($n = \Normalizer::normalize($s, \Normalizer::FORM_C)) !== false) { + $s = $n; + } + + $s = self::unixNewLines($s); + + // remove control characters; leave \t + \n + $s = self::pcre('preg_replace', ['#[\x00-\x08\x0B-\x1F\x7F-\x9F]+#u', '', $s]); + + // right trim + $s = self::pcre('preg_replace', ['#[\t ]+$#m', '', $s]); + + // leading and trailing blank lines + $s = trim($s, "\n"); + + return $s; + } + + + /** @deprecated use Strings::unixNewLines() */ + public static function normalizeNewLines(string $s): string + { + return self::unixNewLines($s); + } + + + /** + * Converts line endings to \n used on Unix-like systems. + * Line endings are: \n, \r, \r\n, U+2028 line separator, U+2029 paragraph separator. + */ + public static function unixNewLines(string $s): string + { + return preg_replace("~\r\n?|\u{2028}|\u{2029}~", "\n", $s); + } + + + /** + * Converts line endings to platform-specific, i.e. \r\n on Windows and \n elsewhere. + * Line endings are: \n, \r, \r\n, U+2028 line separator, U+2029 paragraph separator. + */ + public static function platformNewLines(string $s): string + { + return preg_replace("~\r\n?|\n|\u{2028}|\u{2029}~", PHP_EOL, $s); + } + + + /** + * Converts UTF-8 string to ASCII, ie removes diacritics etc. + */ + public static function toAscii(string $s): string + { + if (!extension_loaded('intl')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires INTL extension that is not loaded.'); + } + + $iconv = defined('ICONV_IMPL') ? trim(ICONV_IMPL, '"\'') : null; + + // remove control characters and check UTF-8 validity + $s = self::pcre('preg_replace', ['#[^\x09\x0A\x0D\x20-\x7E\xA0-\x{2FF}\x{370}-\x{10FFFF}]#u', '', $s]); + + // transliteration (by Transliterator and iconv) is not optimal, replace some characters directly + $s = strtr($s, ["\u{201E}" => '"', "\u{201C}" => '"', "\u{201D}" => '"', "\u{201A}" => "'", "\u{2018}" => "'", "\u{2019}" => "'", "\u{B0}" => '^', "\u{42F}" => 'Ya', "\u{44F}" => 'ya', "\u{42E}" => 'Yu', "\u{44E}" => 'yu', "\u{c4}" => 'Ae', "\u{d6}" => 'Oe', "\u{dc}" => 'Ue', "\u{1e9e}" => 'Ss', "\u{e4}" => 'ae', "\u{f6}" => 'oe', "\u{fc}" => 'ue', "\u{df}" => 'ss']); // „ “ ” ‚ ‘ ’ ° Я я Ю ю Ä Ö Ü ẞ ä ö ü ß + if ($iconv !== 'libiconv') { + $s = strtr($s, ["\u{AE}" => '(R)', "\u{A9}" => '(c)', "\u{2026}" => '...', "\u{AB}" => '<<', "\u{BB}" => '>>', "\u{A3}" => 'lb', "\u{A5}" => 'yen', "\u{B2}" => '^2', "\u{B3}" => '^3', "\u{B5}" => 'u', "\u{B9}" => '^1', "\u{BA}" => 'o', "\u{BF}" => '?', "\u{2CA}" => "'", "\u{2CD}" => '_', "\u{2DD}" => '"', "\u{1FEF}" => '', "\u{20AC}" => 'EUR', "\u{2122}" => 'TM', "\u{212E}" => 'e', "\u{2190}" => '<-', "\u{2191}" => '^', "\u{2192}" => '->', "\u{2193}" => 'V', "\u{2194}" => '<->']); // ® © … « » £ ¥ ² ³ µ ¹ º ¿ ˊ ˍ ˝ ` € ™ ℮ ← ↑ → ↓ ↔ + } + + $s = \Transliterator::create('Any-Latin; Latin-ASCII')->transliterate($s); + // use iconv because The transliterator leaves some characters out of ASCII, eg → ʾ + if ($iconv === 'glibc') { + $s = strtr($s, '?', "\x01"); // temporarily hide ? to distinguish them from the garbage that iconv creates + $s = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); + $s = str_replace(['?', "\x01"], ['', '?'], $s); // remove garbage and restore ? characters + } elseif ($iconv === 'libiconv') { + $s = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $s); + } else { // null or 'unknown' (#216) + $s = self::pcre('preg_replace', ['#[^\x00-\x7F]++#', '', $s]); // remove non-ascii chars + } + + return $s; + } + + + /** + * Modifies the UTF-8 string to the form used in the URL, ie removes diacritics and replaces all characters + * except letters of the English alphabet and numbers with a hyphens. + */ + public static function webalize(string $s, ?string $charlist = null, bool $lower = true): string + { + $s = self::toAscii($s); + if ($lower) { + $s = strtolower($s); + } + + $s = self::pcre('preg_replace', ['#[^a-z0-9' . ($charlist !== null ? preg_quote($charlist, '#') : '') . ']+#i', '-', $s]); + $s = trim($s, '-'); + return $s; + } + + + /** + * Truncates a UTF-8 string to given maximal length, while trying not to split whole words. Only if the string is truncated, + * an ellipsis (or something else set with third argument) is appended to the string. + */ + public static function truncate(string $s, int $maxLen, string $append = "\u{2026}"): string + { + if (self::length($s) > $maxLen) { + $maxLen -= self::length($append); + if ($maxLen < 1) { + return $append; + + } elseif ($matches = self::match($s, '#^.{1,' . $maxLen . '}(?=[\s\x00-/:-@\[-`{-~])#us')) { + return $matches[0] . $append; + + } else { + return self::substring($s, 0, $maxLen) . $append; + } + } + + return $s; + } + + + /** + * Indents a multiline text from the left. Second argument sets how many indentation chars should be used, + * while the indent itself is the third argument (*tab* by default). + */ + public static function indent(string $s, int $level = 1, string $chars = "\t"): string + { + if ($level > 0) { + $s = self::replace($s, '#(?:^|[\r\n]+)(?=[^\r\n])#', '$0' . str_repeat($chars, $level)); + } + + return $s; + } + + + /** + * Converts all characters of UTF-8 string to lower case. + */ + public static function lower(string $s): string + { + return mb_strtolower($s, 'UTF-8'); + } + + + /** + * Converts the first character of a UTF-8 string to lower case and leaves the other characters unchanged. + */ + public static function firstLower(string $s): string + { + return self::lower(self::substring($s, 0, 1)) . self::substring($s, 1); + } + + + /** + * Converts all characters of a UTF-8 string to upper case. + */ + public static function upper(string $s): string + { + return mb_strtoupper($s, 'UTF-8'); + } + + + /** + * Converts the first character of a UTF-8 string to upper case and leaves the other characters unchanged. + */ + public static function firstUpper(string $s): string + { + return self::upper(self::substring($s, 0, 1)) . self::substring($s, 1); + } + + + /** + * Converts the first character of every word of a UTF-8 string to upper case and the others to lower case. + */ + public static function capitalize(string $s): string + { + return mb_convert_case($s, MB_CASE_TITLE, 'UTF-8'); + } + + + /** + * Compares two UTF-8 strings or their parts, without taking character case into account. If length is null, whole strings are compared, + * if it is negative, the corresponding number of characters from the end of the strings is compared, + * otherwise the appropriate number of characters from the beginning is compared. + */ + public static function compare(string $left, string $right, ?int $length = null): bool + { + if (class_exists('Normalizer', false)) { + $left = \Normalizer::normalize($left, \Normalizer::FORM_D); // form NFD is faster + $right = \Normalizer::normalize($right, \Normalizer::FORM_D); // form NFD is faster + } + + if ($length < 0) { + $left = self::substring($left, $length, -$length); + $right = self::substring($right, $length, -$length); + } elseif ($length !== null) { + $left = self::substring($left, 0, $length); + $right = self::substring($right, 0, $length); + } + + return self::lower($left) === self::lower($right); + } + + + /** + * Finds the common prefix of strings or returns empty string if the prefix was not found. + * @param string[] $strings + */ + public static function findPrefix(array $strings): string + { + $first = array_shift($strings); + for ($i = 0; $i < strlen($first); $i++) { + foreach ($strings as $s) { + if (!isset($s[$i]) || $first[$i] !== $s[$i]) { + while ($i && $first[$i - 1] >= "\x80" && $first[$i] >= "\x80" && $first[$i] < "\xC0") { + $i--; + } + + return substr($first, 0, $i); + } + } + } + + return $first; + } + + + /** + * Returns number of characters (not bytes) in UTF-8 string. + * That is the number of Unicode code points which may differ from the number of graphemes. + */ + public static function length(string $s): int + { + return match (true) { + extension_loaded('mbstring') => mb_strlen($s, 'UTF-8'), + extension_loaded('iconv') => iconv_strlen($s, 'UTF-8'), + default => strlen(@utf8_decode($s)), // deprecated + }; + } + + + /** + * Removes all left and right side spaces (or the characters passed as second argument) from a UTF-8 encoded string. + */ + public static function trim(string $s, string $charlist = self::TrimCharacters): string + { + $charlist = preg_quote($charlist, '#'); + return self::replace($s, '#^[' . $charlist . ']+|[' . $charlist . ']+$#Du', ''); + } + + + /** + * Pads a UTF-8 string to given length by prepending the $pad string to the beginning. + * @param non-empty-string $pad + */ + public static function padLeft(string $s, int $length, string $pad = ' '): string + { + $length = max(0, $length - self::length($s)); + $padLen = self::length($pad); + return str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen) . $s; + } + + + /** + * Pads UTF-8 string to given length by appending the $pad string to the end. + * @param non-empty-string $pad + */ + public static function padRight(string $s, int $length, string $pad = ' '): string + { + $length = max(0, $length - self::length($s)); + $padLen = self::length($pad); + return $s . str_repeat($pad, (int) ($length / $padLen)) . self::substring($pad, 0, $length % $padLen); + } + + + /** + * Reverses UTF-8 string. + */ + public static function reverse(string $s): string + { + if (!extension_loaded('iconv')) { + throw new Nette\NotSupportedException(__METHOD__ . '() requires ICONV extension that is not loaded.'); + } + + return iconv('UTF-32LE', 'UTF-8', strrev(iconv('UTF-8', 'UTF-32BE', $s))); + } + + + /** + * Returns part of $haystack before $nth occurence of $needle or returns null if the needle was not found. + * Negative value means searching from the end. + */ + public static function before(string $haystack, string $needle, int $nth = 1): ?string + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null + ? null + : substr($haystack, 0, $pos); + } + + + /** + * Returns part of $haystack after $nth occurence of $needle or returns null if the needle was not found. + * Negative value means searching from the end. + */ + public static function after(string $haystack, string $needle, int $nth = 1): ?string + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null + ? null + : substr($haystack, $pos + strlen($needle)); + } + + + /** + * Returns position in characters of $nth occurence of $needle in $haystack or null if the $needle was not found. + * Negative value of `$nth` means searching from the end. + */ + public static function indexOf(string $haystack, string $needle, int $nth = 1): ?int + { + $pos = self::pos($haystack, $needle, $nth); + return $pos === null + ? null + : self::length(substr($haystack, 0, $pos)); + } + + + /** + * Returns position in characters of $nth occurence of $needle in $haystack or null if the needle was not found. + */ + private static function pos(string $haystack, string $needle, int $nth = 1): ?int + { + if (!$nth) { + return null; + } elseif ($nth > 0) { + if ($needle === '') { + return 0; + } + + $pos = 0; + while (($pos = strpos($haystack, $needle, $pos)) !== false && --$nth) { + $pos++; + } + } else { + $len = strlen($haystack); + if ($needle === '') { + return $len; + } elseif ($len === 0) { + return null; + } + + $pos = $len - 1; + while (($pos = strrpos($haystack, $needle, $pos - $len)) !== false && ++$nth) { + $pos--; + } + } + + return Helpers::falseToNull($pos); + } + + + /** + * Divides the string into arrays according to the regular expression. Expressions in parentheses will be captured and returned as well. + */ + public static function split( + string $subject, + #[Language('RegExp')] + string $pattern, + bool|int $captureOffset = false, + bool $skipEmpty = false, + int $limit = -1, + bool $utf8 = false, + ): array + { + $flags = is_int($captureOffset) // back compatibility + ? $captureOffset + : ($captureOffset ? PREG_SPLIT_OFFSET_CAPTURE : 0) | ($skipEmpty ? PREG_SPLIT_NO_EMPTY : 0); + + $pattern .= $utf8 ? 'u' : ''; + $m = self::pcre('preg_split', [$pattern, $subject, $limit, $flags | PREG_SPLIT_DELIM_CAPTURE]); + return $utf8 && $captureOffset + ? self::bytesToChars($subject, [$m])[0] + : $m; + } + + + /** + * Searches the string for the part matching the regular expression and returns + * an array with the found expression and individual subexpressions, or `null`. + */ + public static function match( + string $subject, + #[Language('RegExp')] + string $pattern, + bool|int $captureOffset = false, + int $offset = 0, + bool $unmatchedAsNull = false, + bool $utf8 = false, + ): ?array + { + $flags = is_int($captureOffset) // back compatibility + ? $captureOffset + : ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0); + + if ($utf8) { + $offset = strlen(self::substring($subject, 0, $offset)); + $pattern .= 'u'; + } + + if ($offset > strlen($subject)) { + return null; + } elseif (!self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset])) { + return null; + } elseif ($utf8 && $captureOffset) { + return self::bytesToChars($subject, [$m])[0]; + } else { + return $m; + } + } + + + /** + * Searches the string for all occurrences matching the regular expression and + * returns an array of arrays containing the found expression and each subexpression. + * @return ($lazy is true ? \Generator : array[]) + */ + public static function matchAll( + string $subject, + #[Language('RegExp')] + string $pattern, + bool|int $captureOffset = false, + int $offset = 0, + bool $unmatchedAsNull = false, + bool $patternOrder = false, + bool $utf8 = false, + bool $lazy = false, + ): array|\Generator + { + if ($utf8) { + $offset = strlen(self::substring($subject, 0, $offset)); + $pattern .= 'u'; + } + + if ($lazy) { + $flags = PREG_OFFSET_CAPTURE | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0); + return (function () use ($utf8, $captureOffset, $flags, $subject, $pattern, $offset) { + $counter = 0; + while ( + $offset <= strlen($subject) - ($counter ? 1 : 0) + && self::pcre('preg_match', [$pattern, $subject, &$m, $flags, $offset]) + ) { + $offset = $m[0][1] + max(1, strlen($m[0][0])); + if (!$captureOffset) { + $m = array_map(fn($item) => $item[0], $m); + } elseif ($utf8) { + $m = self::bytesToChars($subject, [$m])[0]; + } + yield $counter++ => $m; + } + })(); + } + + if ($offset > strlen($subject)) { + return []; + } + + $flags = is_int($captureOffset) // back compatibility + ? $captureOffset + : ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0) | ($patternOrder ? PREG_PATTERN_ORDER : 0); + + self::pcre('preg_match_all', [ + $pattern, $subject, &$m, + ($flags & PREG_PATTERN_ORDER) ? $flags : ($flags | PREG_SET_ORDER), + $offset, + ]); + return $utf8 && $captureOffset + ? self::bytesToChars($subject, $m) + : $m; + } + + + /** + * Replaces all occurrences matching regular expression $pattern which can be string or array in the form `pattern => replacement`. + */ + public static function replace( + string $subject, + #[Language('RegExp')] + string|array $pattern, + string|callable $replacement = '', + int $limit = -1, + bool $captureOffset = false, + bool $unmatchedAsNull = false, + bool $utf8 = false, + ): string + { + if (is_object($replacement) || is_array($replacement)) { + if (!is_callable($replacement, false, $textual)) { + throw new Nette\InvalidStateException("Callback '$textual' is not callable."); + } + + $flags = ($captureOffset ? PREG_OFFSET_CAPTURE : 0) | ($unmatchedAsNull ? PREG_UNMATCHED_AS_NULL : 0); + if ($utf8) { + $pattern .= 'u'; + if ($captureOffset) { + $replacement = fn($m) => $replacement(self::bytesToChars($subject, [$m])[0]); + } + } + + return self::pcre('preg_replace_callback', [$pattern, $replacement, $subject, $limit, 0, $flags]); + + } elseif (is_array($pattern) && is_string(key($pattern))) { + $replacement = array_values($pattern); + $pattern = array_keys($pattern); + } + + if ($utf8) { + $pattern = array_map(fn($item) => $item . 'u', (array) $pattern); + } + + return self::pcre('preg_replace', [$pattern, $replacement, $subject, $limit]); + } + + + private static function bytesToChars(string $s, array $groups): array + { + $lastBytes = $lastChars = 0; + foreach ($groups as &$matches) { + foreach ($matches as &$match) { + if ($match[1] > $lastBytes) { + $lastChars += self::length(substr($s, $lastBytes, $match[1] - $lastBytes)); + } elseif ($match[1] < $lastBytes) { + $lastChars -= self::length(substr($s, $match[1], $lastBytes - $match[1])); + } + + $lastBytes = $match[1]; + $match[1] = $lastChars; + } + } + + return $groups; + } + + + /** @internal */ + public static function pcre(string $func, array $args) + { + $res = Callback::invokeSafe($func, $args, function (string $message) use ($args): void { + // compile-time error, not detectable by preg_last_error + throw new RegexpException($message . ' in pattern: ' . implode(' or ', (array) $args[0])); + }); + + if (($code = preg_last_error()) // run-time error, but preg_last_error & return code are liars + && ($res === null || !in_array($func, ['preg_filter', 'preg_replace_callback', 'preg_replace'], true)) + ) { + throw new RegexpException(preg_last_error_msg() + . ' (pattern: ' . implode(' or ', (array) $args[0]) . ')', $code); + } + + return $res; + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Type.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Type.php new file mode 100644 index 00000000000..92aac80de1d --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Type.php @@ -0,0 +1,302 @@ + */ + private array $types; + private bool $simple; + private string $kind; // | & + + + /** + * Creates a Type object based on reflection. Resolves self, static and parent to the actual class name. + * If the subject has no type, it returns null. + */ + public static function fromReflection( + \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $reflection, + ): ?self + { + $type = $reflection instanceof \ReflectionFunctionAbstract + ? $reflection->getReturnType() ?? ($reflection instanceof \ReflectionMethod ? $reflection->getTentativeReturnType() : null) + : $reflection->getType(); + + return $type ? self::fromReflectionType($type, $reflection, asObject: true) : null; + } + + + private static function fromReflectionType(\ReflectionType $type, $of, bool $asObject): self|string + { + if ($type instanceof \ReflectionNamedType) { + $name = self::resolve($type->getName(), $of); + return $asObject + ? new self($type->allowsNull() && $name !== 'mixed' ? [$name, 'null'] : [$name]) + : $name; + + } elseif ($type instanceof \ReflectionUnionType || $type instanceof \ReflectionIntersectionType) { + return new self( + array_map(fn($t) => self::fromReflectionType($t, $of, asObject: false), $type->getTypes()), + $type instanceof \ReflectionUnionType ? '|' : '&', + ); + + } else { + throw new Nette\InvalidStateException('Unexpected type of ' . Reflection::toString($of)); + } + } + + + /** + * Creates the Type object according to the text notation. + */ + public static function fromString(string $type): self + { + if (!Validators::isTypeDeclaration($type)) { + throw new Nette\InvalidArgumentException("Invalid type '$type'."); + } + + if ($type[0] === '?') { + return new self([substr($type, 1), 'null']); + } + + $unions = []; + foreach (explode('|', $type) as $part) { + $part = explode('&', trim($part, '()')); + $unions[] = count($part) === 1 ? $part[0] : new self($part, '&'); + } + + return count($unions) === 1 && $unions[0] instanceof self + ? $unions[0] + : new self($unions); + } + + + /** + * Creates a Type object based on the actual type of value. + */ + public static function fromValue(mixed $value): self + { + $type = get_debug_type($value); + if (is_resource($value)) { + $type = 'mixed'; + } elseif (str_ends_with($type, '@anonymous')) { + $parent = substr($type, 0, -10); + $type = $parent === 'class' ? 'object' : $parent; + } + + return new self([$type]); + } + + + /** + * Resolves 'self', 'static' and 'parent' to the actual class name. + */ + public static function resolve( + string $type, + \ReflectionFunctionAbstract|\ReflectionParameter|\ReflectionProperty $of, + ): string + { + $lower = strtolower($type); + if ($of instanceof \ReflectionFunction) { + return $type; + } elseif ($lower === 'self') { + return $of->getDeclaringClass()->name; + } elseif ($lower === 'static') { + return ($of instanceof ReflectionMethod ? $of->getOriginalClass() : $of->getDeclaringClass())->name; + } elseif ($lower === 'parent' && $of->getDeclaringClass()->getParentClass()) { + return $of->getDeclaringClass()->getParentClass()->name; + } else { + return $type; + } + } + + + private function __construct(array $types, string $kind = '|') + { + $o = array_search('null', $types, strict: true); + if ($o !== false) { // null as last + array_splice($types, $o, 1); + $types[] = 'null'; + } + + $this->types = $types; + $this->simple = is_string($types[0]) && ($types[1] ?? 'null') === 'null'; + $this->kind = count($types) > 1 ? $kind : ''; + } + + + public function __toString(): string + { + $multi = count($this->types) > 1; + if ($this->simple) { + return ($multi ? '?' : '') . $this->types[0]; + } + + $res = []; + foreach ($this->types as $type) { + $res[] = $type instanceof self && $multi ? "($type)" : $type; + } + return implode($this->kind, $res); + } + + + /** + * Returns a type that accepts both the current type and the given type. + */ + public function with(string|self $type): self + { + $type = is_string($type) ? self::fromString($type) : $type; + return match (true) { + $this->allows($type) => $this, + $type->allows($this) => $type, + default => new self(array_unique( + array_merge($this->isIntersection() ? [$this] : $this->types, $type->isIntersection() ? [$type] : $type->types), + SORT_REGULAR, + ), '|'), + }; + } + + + /** + * Returns the array of subtypes that make up the compound type as strings. + * @return array + */ + public function getNames(): array + { + return array_map(fn($t) => $t instanceof self ? $t->getNames() : $t, $this->types); + } + + + /** + * Returns the array of subtypes that make up the compound type as Type objects: + * @return self[] + */ + public function getTypes(): array + { + return array_map(fn($t) => $t instanceof self ? $t : new self([$t]), $this->types); + } + + + /** + * Returns the type name for simple types, otherwise null. + */ + public function getSingleName(): ?string + { + return $this->simple + ? $this->types[0] + : null; + } + + + /** + * Returns true whether it is a union type. + */ + public function isUnion(): bool + { + return $this->kind === '|'; + } + + + /** + * Returns true whether it is an intersection type. + */ + public function isIntersection(): bool + { + return $this->kind === '&'; + } + + + /** + * Returns true whether it is a simple type. Single nullable types are also considered to be simple types. + */ + public function isSimple(): bool + { + return $this->simple; + } + + + #[\Deprecated('use isSimple()')] + public function isSingle(): bool + { + return $this->simple; + } + + + /** + * Returns true whether the type is both a simple and a PHP built-in type. + */ + public function isBuiltin(): bool + { + return $this->simple && Validators::isBuiltinType($this->types[0]); + } + + + /** + * Returns true whether the type is both a simple and a class name. + */ + public function isClass(): bool + { + return $this->simple && !Validators::isBuiltinType($this->types[0]); + } + + + /** + * Determines if type is special class name self/parent/static. + */ + public function isClassKeyword(): bool + { + return $this->simple && Validators::isClassKeyword($this->types[0]); + } + + + /** + * Verifies type compatibility. For example, it checks if a value of a certain type could be passed as a parameter. + */ + public function allows(string|self $type): bool + { + if ($this->types === ['mixed']) { + return true; + } + + $type = is_string($type) ? self::fromString($type) : $type; + return $type->isUnion() + ? Arrays::every($type->types, fn($t) => $this->allowsAny($t instanceof self ? $t->types : [$t])) + : $this->allowsAny($type->types); + } + + + private function allowsAny(array $givenTypes): bool + { + return $this->isUnion() + ? Arrays::some($this->types, fn($t) => $this->allowsAll($t instanceof self ? $t->types : [$t], $givenTypes)) + : $this->allowsAll($this->types, $givenTypes); + } + + + private function allowsAll(array $ourTypes, array $givenTypes): bool + { + return Arrays::every( + $ourTypes, + fn($ourType) => Arrays::some( + $givenTypes, + fn($givenType) => Validators::isBuiltinType($ourType) + ? strcasecmp($ourType, $givenType) === 0 + : is_a($givenType, $ourType, allow_string: true), + ), + ); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/Validators.php b/tools/.phpstan/vendor/nette/utils/src/Utils/Validators.php new file mode 100644 index 00000000000..940c3eb43f7 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/Validators.php @@ -0,0 +1,417 @@ + 1, 'int' => 1, 'float' => 1, 'bool' => 1, 'array' => 1, 'object' => 1, + 'callable' => 1, 'iterable' => 1, 'void' => 1, 'null' => 1, 'mixed' => 1, 'false' => 1, + 'never' => 1, 'true' => 1, + ]; + + /** @var array */ + protected static $validators = [ + // PHP types + 'array' => 'is_array', + 'bool' => 'is_bool', + 'boolean' => 'is_bool', + 'float' => 'is_float', + 'int' => 'is_int', + 'integer' => 'is_int', + 'null' => 'is_null', + 'object' => 'is_object', + 'resource' => 'is_resource', + 'scalar' => 'is_scalar', + 'string' => 'is_string', + + // pseudo-types + 'callable' => [self::class, 'isCallable'], + 'iterable' => 'is_iterable', + 'list' => [Arrays::class, 'isList'], + 'mixed' => [self::class, 'isMixed'], + 'none' => [self::class, 'isNone'], + 'number' => [self::class, 'isNumber'], + 'numeric' => [self::class, 'isNumeric'], + 'numericint' => [self::class, 'isNumericInt'], + + // string patterns + 'alnum' => 'ctype_alnum', + 'alpha' => 'ctype_alpha', + 'digit' => 'ctype_digit', + 'lower' => 'ctype_lower', + 'pattern' => null, + 'space' => 'ctype_space', + 'unicode' => [self::class, 'isUnicode'], + 'upper' => 'ctype_upper', + 'xdigit' => 'ctype_xdigit', + + // syntax validation + 'email' => [self::class, 'isEmail'], + 'identifier' => [self::class, 'isPhpIdentifier'], + 'uri' => [self::class, 'isUri'], + 'url' => [self::class, 'isUrl'], + + // environment validation + 'class' => 'class_exists', + 'interface' => 'interface_exists', + 'directory' => 'is_dir', + 'file' => 'is_file', + 'type' => [self::class, 'isType'], + ]; + + /** @var array */ + protected static $counters = [ + 'string' => 'strlen', + 'unicode' => [Strings::class, 'length'], + 'array' => 'count', + 'list' => 'count', + 'alnum' => 'strlen', + 'alpha' => 'strlen', + 'digit' => 'strlen', + 'lower' => 'strlen', + 'space' => 'strlen', + 'upper' => 'strlen', + 'xdigit' => 'strlen', + ]; + + + /** + * Verifies that the value is of expected types separated by pipe. + * @throws AssertionException + */ + public static function assert(mixed $value, string $expected, string $label = 'variable'): void + { + if (!static::is($value, $expected)) { + $expected = str_replace(['|', ':'], [' or ', ' in range '], $expected); + $translate = ['boolean' => 'bool', 'integer' => 'int', 'double' => 'float', 'NULL' => 'null']; + $type = $translate[gettype($value)] ?? gettype($value); + if (is_int($value) || is_float($value) || (is_string($value) && strlen($value) < 40)) { + $type .= ' ' . var_export($value, return: true); + } elseif (is_object($value)) { + $type .= ' ' . $value::class; + } + + throw new AssertionException("The $label expects to be $expected, $type given."); + } + } + + + /** + * Verifies that element $key in array is of expected types separated by pipe. + * @param mixed[] $array + * @throws AssertionException + */ + public static function assertField( + array $array, + $key, + ?string $expected = null, + string $label = "item '%' in array", + ): void + { + if (!array_key_exists($key, $array)) { + throw new AssertionException('Missing ' . str_replace('%', $key, $label) . '.'); + + } elseif ($expected) { + static::assert($array[$key], $expected, str_replace('%', $key, $label)); + } + } + + + /** + * Verifies that the value is of expected types separated by pipe. + */ + public static function is(mixed $value, string $expected): bool + { + foreach (explode('|', $expected) as $item) { + if (str_ends_with($item, '[]')) { + if (is_iterable($value) && self::everyIs($value, substr($item, 0, -2))) { + return true; + } + + continue; + } elseif (str_starts_with($item, '?')) { + $item = substr($item, 1); + if ($value === null) { + return true; + } + } + + [$type] = $item = explode(':', $item, 2); + if (isset(static::$validators[$type])) { + try { + if (!static::$validators[$type]($value)) { + continue; + } + } catch (\TypeError $e) { + continue; + } + } elseif ($type === 'pattern') { + if (Strings::match($value, '|^' . ($item[1] ?? '') . '$|D')) { + return true; + } + + continue; + } elseif (!$value instanceof $type) { + continue; + } + + if (isset($item[1])) { + $length = $value; + if (isset(static::$counters[$type])) { + $length = static::$counters[$type]($value); + } + + $range = explode('..', $item[1]); + if (!isset($range[1])) { + $range[1] = $range[0]; + } + + if (($range[0] !== '' && $length < $range[0]) || ($range[1] !== '' && $length > $range[1])) { + continue; + } + } + + return true; + } + + return false; + } + + + /** + * Finds whether all values are of expected types separated by pipe. + * @param mixed[] $values + */ + public static function everyIs(iterable $values, string $expected): bool + { + foreach ($values as $value) { + if (!static::is($value, $expected)) { + return false; + } + } + + return true; + } + + + /** + * Checks if the value is an integer or a float. + * @return ($value is int|float ? true : false) + */ + public static function isNumber(mixed $value): bool + { + return is_int($value) || is_float($value); + } + + + /** + * Checks if the value is an integer or a integer written in a string. + * @return ($value is non-empty-string ? bool : ($value is int ? true : false)) + */ + public static function isNumericInt(mixed $value): bool + { + return is_int($value) || (is_string($value) && preg_match('#^[+-]?[0-9]+$#D', $value)); + } + + + /** + * Checks if the value is a number or a number written in a string. + * @return ($value is non-empty-string ? bool : ($value is int|float ? true : false)) + */ + public static function isNumeric(mixed $value): bool + { + return is_float($value) || is_int($value) || (is_string($value) && preg_match('#^[+-]?([0-9]++\.?[0-9]*|\.[0-9]+)$#D', $value)); + } + + + /** + * Checks if the value is a syntactically correct callback. + */ + public static function isCallable(mixed $value): bool + { + return $value && is_callable($value, syntax_only: true); + } + + + /** + * Checks if the value is a valid UTF-8 string. + */ + public static function isUnicode(mixed $value): bool + { + return is_string($value) && preg_match('##u', $value); + } + + + /** + * Checks if the value is 0, '', false or null. + * @return ($value is 0|''|false|null ? true : false) + */ + public static function isNone(mixed $value): bool + { + return $value == null; // intentionally == + } + + + /** @internal */ + public static function isMixed(): bool + { + return true; + } + + + /** + * Checks if a variable is a zero-based integer indexed array. + * @deprecated use Nette\Utils\Arrays::isList + * @return ($value is list ? true : false) + */ + public static function isList(mixed $value): bool + { + return Arrays::isList($value); + } + + + /** + * Checks if the value is in the given range [min, max], where the upper or lower limit can be omitted (null). + * Numbers, strings and DateTime objects can be compared. + */ + public static function isInRange(mixed $value, array $range): bool + { + if ($value === null || !(isset($range[0]) || isset($range[1]))) { + return false; + } + + $limit = $range[0] ?? $range[1]; + if (is_string($limit)) { + $value = (string) $value; + } elseif ($limit instanceof \DateTimeInterface) { + if (!$value instanceof \DateTimeInterface) { + return false; + } + } elseif (is_numeric($value)) { + $value *= 1; + } else { + return false; + } + + return (!isset($range[0]) || ($value >= $range[0])) && (!isset($range[1]) || ($value <= $range[1])); + } + + + /** + * Checks if the value is a valid email address. It does not verify that the domain actually exists, only the syntax is verified. + */ + public static function isEmail(string $value): bool + { + $atom = "[-a-z0-9!#$%&'*+/=?^_`{|}~]"; // RFC 5322 unquoted characters in local-part + $alpha = "a-z\x80-\xFF"; // superset of IDN + return (bool) preg_match(<< \\? (? [a-zA-Z_\x7f-\xff][\w\x7f-\xff]*) (\\ (?&name))* ) | + (? (?&type) (& (?&type))+ ) | + (? (?&type) | \( (?&intersection) \) ) (\| (?&upart))+ + )$~xAD + XX, $type); + } +} diff --git a/tools/.phpstan/vendor/nette/utils/src/Utils/exceptions.php b/tools/.phpstan/vendor/nette/utils/src/Utils/exceptions.php new file mode 100644 index 00000000000..30805ea3c48 --- /dev/null +++ b/tools/.phpstan/vendor/nette/utils/src/Utils/exceptions.php @@ -0,0 +1,50 @@ + + array ( + 'install_path' => '/usr/local/src/phpunit/tools/.phpstan/vendor/ergebnis/phpstan-rules', + 'relative_install_path' => '../../../ergebnis/phpstan-rules', + 'extra' => + array ( + 'includes' => + array ( + 0 => 'rules.neon', + ), + ), + 'version' => '2.12.0', + 'phpstanVersionConstraint' => '>=2.1.8.0-dev, <3.0.0.0-dev', + ), + 'phpstan/phpstan-strict-rules' => + array ( + 'install_path' => '/usr/local/src/phpunit/tools/.phpstan/vendor/phpstan/phpstan-strict-rules', + 'relative_install_path' => '../../phpstan-strict-rules', + 'extra' => + array ( + 'includes' => + array ( + 0 => 'rules.neon', + ), + ), + 'version' => '2.0.7', + 'phpstanVersionConstraint' => '>=2.1.29.0-dev, <3.0.0.0-dev', + ), + 'tomasvotruba/type-coverage' => + array ( + 'install_path' => '/usr/local/src/phpunit/tools/.phpstan/vendor/tomasvotruba/type-coverage', + 'relative_install_path' => '../../../tomasvotruba/type-coverage', + 'extra' => + array ( + 'includes' => + array ( + 0 => 'config/extension.neon', + ), + ), + 'version' => '2.1.0', + 'phpstanVersionConstraint' => '>=2.0.0.0-dev, <3.0.0.0-dev', + ), +); + + public const NOT_INSTALLED = array ( +); + + /** @var string|null */ + public const PHPSTAN_VERSION_CONSTRAINT = '>=2.1.29.0-dev, <3.0.0.0-dev'; + + private function __construct() + { + } + +} diff --git a/tools/.phpstan/vendor/phpstan/extension-installer/src/Plugin.php b/tools/.phpstan/vendor/phpstan/extension-installer/src/Plugin.php new file mode 100644 index 00000000000..ec757351f91 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/extension-installer/src/Plugin.php @@ -0,0 +1,228 @@ + + */ + public static function getSubscribedEvents(): array + { + return [ + ScriptEvents::POST_INSTALL_CMD => 'process', + ScriptEvents::POST_UPDATE_CMD => 'process', + ]; + } + + public function process(Event $event): void + { + $io = $event->getIO(); + + if (!file_exists(__DIR__)) { + $io->write('phpstan/extension-installer: Package not found (probably scheduled for removal); extensions installation skipped.'); + return; + } + + $composer = $event->getComposer(); + $installationManager = $composer->getInstallationManager(); + + $generatedConfigFilePath = __DIR__ . '/GeneratedConfig.php'; + $oldGeneratedConfigFileHash = null; + if (is_file($generatedConfigFilePath)) { + $oldGeneratedConfigFileHash = md5_file($generatedConfigFilePath); + } + $notInstalledPackages = []; + $installedPackages = []; + $ignoredPackages = []; + + $data = []; + $fs = new Filesystem(); + $ignore = []; + + $packageExtra = $composer->getPackage()->getExtra(); + + if (isset($packageExtra['phpstan/extension-installer']['ignore'])) { + $ignore = $packageExtra['phpstan/extension-installer']['ignore']; + } + + $phpstanVersionConstraints = []; + + foreach ($composer->getRepositoryManager()->getLocalRepository()->getPackages() as $package) { + if ( + $package->getType() !== 'phpstan-extension' + && !isset($package->getExtra()['phpstan']) + ) { + if ( + strpos($package->getName(), 'phpstan') !== false + && !in_array($package->getName(), [ + 'phpstan/phpstan', + 'phpstan/phpstan-shim', + 'phpstan/phpdoc-parser', + 'phpstan/extension-installer', + ], true) + ) { + $notInstalledPackages[$package->getName()] = $package->getFullPrettyVersion(); + } + continue; + } + + if (in_array($package->getName(), $ignore, true)) { + $ignoredPackages[] = $package->getName(); + continue; + } + + $installPath = $installationManager->getInstallPath($package); + if ($installPath === null) { + continue; + } + + $absoluteInstallPath = $fs->isAbsolutePath($installPath) + ? $installPath + : getcwd() . DIRECTORY_SEPARATOR . $installPath; + + $packageRequires = $package->getRequires(); + $phpstanConstraint = null; + if (array_key_exists('phpstan/phpstan', $packageRequires)) { + $phpstanConstraint = $packageRequires['phpstan/phpstan']->getConstraint(); + if ($phpstanConstraint->getLowerBound()->isZero()) { + continue; + } + if ($phpstanConstraint->getUpperBound()->isPositiveInfinity()) { + continue; + } + $phpstanVersionConstraints[] = $phpstanConstraint; + } + + $data[$package->getName()] = [ + 'install_path' => $absoluteInstallPath, + 'relative_install_path' => $fs->findShortestPath(dirname($generatedConfigFilePath), $absoluteInstallPath, true), + 'extra' => $package->getExtra()['phpstan'] ?? null, + 'version' => $package->getFullPrettyVersion(), + 'phpstanVersionConstraint' => $phpstanConstraint !== null ? $this->constraintIntoString($phpstanConstraint) : null, + ]; + + $installedPackages[$package->getName()] = true; + } + + $phpstanVersionConstraint = null; + if (count($phpstanVersionConstraints) > 0 && class_exists(Intervals::class)) { + if (count($phpstanVersionConstraints) === 1) { + $multiConstraint = $phpstanVersionConstraints[0]; + } else { + $multiConstraint = new MultiConstraint($phpstanVersionConstraints); + } + $phpstanVersionConstraint = $this->constraintIntoString(Intervals::compactConstraint($multiConstraint)); + } + + ksort($data); + ksort($installedPackages); + ksort($notInstalledPackages); + sort($ignoredPackages); + + $generatedConfigFileContents = sprintf(self::$generatedFileTemplate, var_export($data, true), var_export($notInstalledPackages, true), var_export($phpstanVersionConstraint, true)); + file_put_contents($generatedConfigFilePath, $generatedConfigFileContents); + $io->write('phpstan/extension-installer: Extensions installed'); + + if ($oldGeneratedConfigFileHash === md5($generatedConfigFileContents)) { + return; + } + + foreach (array_keys($installedPackages) as $name) { + $io->write(sprintf('> %s: installed', $name)); + } + + foreach (array_keys($notInstalledPackages) as $name) { + $io->write(sprintf('> %s: not supported', $name)); + } + + foreach ($ignoredPackages as $name) { + $io->write(sprintf('> %s: ignored', $name)); + } + } + + private function constraintIntoString(ConstraintInterface $constraint): string + { + return sprintf( + '%s%s, %s%s', + $constraint->getLowerBound()->isInclusive() ? '>=' : '>', + $constraint->getLowerBound()->getVersion(), + $constraint->getUpperBound()->isInclusive() ? '<=' : '<', + $constraint->getUpperBound()->getVersion() + ); + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/.editorconfig b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/.editorconfig new file mode 100644 index 00000000000..5d66bc427b8 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/.editorconfig @@ -0,0 +1,27 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = true +charset = utf-8 +trim_trailing_whitespace = true + +[*.{php,phpt}] +indent_style = tab +indent_size = 4 + +[*.xml] +indent_style = tab +indent_size = 4 + +[*.neon] +indent_style = tab +indent_size = 4 + +[*.{yaml,yml}] +indent_style = space +indent_size = 2 + +[composer.json] +indent_style = tab +indent_size = 4 diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/LICENSE b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/LICENSE new file mode 100644 index 00000000000..52fba1e23bb --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2016 Ondřej Mirtes +Copyright (c) 2025 PHPStan s.r.o. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/README.md b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/README.md new file mode 100644 index 00000000000..3a60ec8e171 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/README.md @@ -0,0 +1,106 @@ +# Extra strict and opinionated rules for PHPStan + +[![Build](https://github.com/phpstan/phpstan-strict-rules/workflows/Build/badge.svg)](https://github.com/phpstan/phpstan-strict-rules/actions) +[![Latest Stable Version](https://poser.pugx.org/phpstan/phpstan-strict-rules/v/stable)](https://packagist.org/packages/phpstan/phpstan-strict-rules) +[![License](https://poser.pugx.org/phpstan/phpstan-strict-rules/license)](https://packagist.org/packages/phpstan/phpstan-strict-rules) + +[PHPStan](https://phpstan.org/) focuses on finding bugs in your code. But in PHP there's a lot of leeway in how stuff can be written. This repository contains additional rules that revolve around strictly and strongly typed code with no loose casting for those who want additional safety in extremely defensive programming: + +| Configuration Parameters | Rule Description | +|:---------------------------------------|:--------------------------------------------------------------------------------------------------------| +| `booleansInConditions` | Require booleans in `if`, `elseif`, ternary operator, after `!`, and on both sides of `&&` and `\|\|`. | +| `booleansInLoopConditions` | Require booleans in `while` and `do while` loop conditions. | +| `numericOperandsInArithmeticOperators` | Require numeric operand in `+$var`, `-$var`, `$var++`, `$var--`, `++$var` and `--$var`. | +| `numericOperandsInArithmeticOperators` | Require numeric operand in `$var++`, `$var--`, `++$var`and `--$var`. | +| `strictFunctionCalls` | These functions contain a `$strict` parameter for better type safety, it must be set to `true`:
    * `in_array` (3rd parameter)
    * `array_search` (3rd parameter)
    * `array_keys` (3rd parameter; only if the 2nd parameter `$search_value` is provided)
    * `base64_decode` (2nd parameter). | +| `overwriteVariablesWithLoop` | * Disallow overwriting variables with `foreach` key and value variables.
    * Disallow overwriting variables with `for` loop initial assignment. | +| `switchConditionsMatchingType` | Types in `switch` condition and `case` value must match. PHP compares them loosely by default and that can lead to unexpected results. | +| `dynamicCallOnStaticMethod` | Check that statically declared methods are called statically. | +| `disallowedEmpty` | Disallow `empty()` - it's a very loose comparison (see [manual](https://php.net/empty)), it's recommended to use more strict one. | +| `disallowedShortTernary` | Disallow short ternary operator (`?:`) - implies weak comparison, it's recommended to use null coalesce operator (`??`) or ternary operator with strict condition. | +| `noVariableVariables` | Disallow variable variables (`$$foo`, `$this->$method()` etc.). | +| `checkAlwaysTrueInstanceof`, `checkAlwaysTrueCheckTypeFunctionCall`, `checkAlwaysTrueStrictComparison` | Always true `instanceof`, type-checking `is_*` functions and strict comparisons `===`/`!==`. These checks can be turned off by setting `checkAlwaysTrueInstanceof`, `checkAlwaysTrueCheckTypeFunctionCall` and `checkAlwaysTrueStrictComparison` to false. | +| | Correct case for referenced and called function names. | +| `matchingInheritedMethodNames` | Correct case for inherited and implemented method names. | +| | Contravariance for parameter types and covariance for return types in inherited methods (also known as Liskov substitution principle - LSP).| +| | Check LSP even for static methods. | +| `requireParentConstructorCall` | Require calling parent constructor. | +| `disallowedBacktick` | Disallow usage of backtick operator (`` $ls = `ls -la` ``). | +| `closureUsesThis` | Closure should use `$this` directly instead of using `$this` variable indirectly. | + +Additional rules are coming in subsequent releases! + + +## Installation + +To use this extension, require it in [Composer](https://getcomposer.org/): + +``` +composer require --dev phpstan/phpstan-strict-rules +``` + +If you also install [phpstan/extension-installer](https://github.com/phpstan/extension-installer) then you're all set! + +
    + Manual installation + +If you don't want to use `phpstan/extension-installer`, include rules.neon in your project's PHPStan config: + +``` +includes: + - vendor/phpstan/phpstan-strict-rules/rules.neon +``` +
    + +## Disabling rules + +You can disable rules using configuration parameters: + +```neon +parameters: + strictRules: + disallowedLooseComparison: false + booleansInConditions: false + booleansInLoopConditions: false + uselessCast: false + requireParentConstructorCall: false + disallowedBacktick: false + disallowedEmpty: false + disallowedImplicitArrayCreation: false + disallowedShortTernary: false + overwriteVariablesWithLoop: false + closureUsesThis: false + matchingInheritedMethodNames: false + numericOperandsInArithmeticOperators: false + strictFunctionCalls: false + dynamicCallOnStaticMethod: false + switchConditionsMatchingType: false + noVariableVariables: false + strictArrayFilter: false + illegalConstructorMethodCall: false +``` + +Aside from introducing new custom rules, phpstan-strict-rules also [change the default values of some configuration parameters](./rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis). + +## Enabling rules one-by-one + +If you don't want to start using all the available strict rules at once but only one or two, you can! + +You can disable all rules from the included `rules.neon` with: + +```neon +parameters: + strictRules: + allRules: false +``` + +Then you can re-enable individual rules with configuration parameters: + +```neon +parameters: + strictRules: + allRules: false + booleansInConditions: true +``` + +Even with `strictRules.allRules` set to `false`, part of this package is still in effect. That's because phpstan-strict-rules also [change the default values of some configuration parameters](./rules.neon#L1) that are present in PHPStan itself. These parameters are [documented on phpstan.org](https://phpstan.org/config-reference#stricter-analysis). diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/composer.json b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/composer.json new file mode 100644 index 00000000000..bc72c58111d --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/composer.json @@ -0,0 +1,43 @@ +{ + "name": "phpstan/phpstan-strict-rules", + "type": "phpstan-extension", + "description": "Extra strict and opinionated rules for PHPStan", + "license": [ + "MIT" + ], + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.1.29" + }, + "require-dev": { + "php-parallel-lint/php-parallel-lint": "^1.2", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6" + }, + "config": { + "platform": { + "php": "7.4.6" + }, + "sort-packages": true + }, + "extra": { + "phpstan": { + "includes": [ + "rules.neon" + ] + } + }, + "autoload": { + "psr-4": { + "PHPStan\\": "src/" + } + }, + "autoload-dev": { + "classmap": [ + "tests/" + ] + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/rules.neon b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/rules.neon new file mode 100644 index 00000000000..0def6d8784c --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/rules.neon @@ -0,0 +1,302 @@ +parameters: + strictRulesInstalled: true + polluteScopeWithLoopInitialAssignments: false + polluteScopeWithAlwaysIterableForeach: false + polluteScopeWithBlock: false + checkDynamicProperties: true + checkExplicitMixedMissingReturn: true + checkFunctionNameCase: true + checkInternalClassCaseSensitivity: true + reportMaybesInMethodSignatures: true + reportStaticMethodSignatures: true + reportMaybesInPropertyPhpDocTypes: true + reportWrongPhpDocTypeInVarTag: true + checkStrictPrintfPlaceholderTypes: true + strictRules: + allRules: true + disallowedLooseComparison: %strictRules.allRules% + booleansInConditions: %strictRules.allRules% + booleansInLoopConditions: [%strictRules.allRules%, %featureToggles.bleedingEdge%] + uselessCast: %strictRules.allRules% + requireParentConstructorCall: %strictRules.allRules% + disallowedBacktick: %strictRules.allRules% + disallowedEmpty: %strictRules.allRules% + disallowedImplicitArrayCreation: %strictRules.allRules% + disallowedShortTernary: %strictRules.allRules% + overwriteVariablesWithLoop: %strictRules.allRules% + closureUsesThis: %strictRules.allRules% + matchingInheritedMethodNames: %strictRules.allRules% + numericOperandsInArithmeticOperators: %strictRules.allRules% + strictFunctionCalls: %strictRules.allRules% + dynamicCallOnStaticMethod: %strictRules.allRules% + switchConditionsMatchingType: %strictRules.allRules% + noVariableVariables: %strictRules.allRules% + strictArrayFilter: %strictRules.allRules% + illegalConstructorMethodCall: %strictRules.allRules% + +parametersSchema: + strictRules: structure([ + allRules: anyOf(bool(), arrayOf(bool())), + disallowedLooseComparison: anyOf(bool(), arrayOf(bool())), + booleansInConditions: anyOf(bool(), arrayOf(bool())) + booleansInLoopConditions: anyOf(bool(), arrayOf(bool())) + uselessCast: anyOf(bool(), arrayOf(bool())) + requireParentConstructorCall: anyOf(bool(), arrayOf(bool())) + disallowedBacktick: anyOf(bool(), arrayOf(bool())) + disallowedEmpty: anyOf(bool(), arrayOf(bool())) + disallowedImplicitArrayCreation: anyOf(bool(), arrayOf(bool())) + disallowedShortTernary: anyOf(bool(), arrayOf(bool())) + overwriteVariablesWithLoop: anyOf(bool(), arrayOf(bool())) + closureUsesThis: anyOf(bool(), arrayOf(bool())) + matchingInheritedMethodNames: anyOf(bool(), arrayOf(bool())) + numericOperandsInArithmeticOperators: anyOf(bool(), arrayOf(bool())) + strictFunctionCalls: anyOf(bool(), arrayOf(bool())) + dynamicCallOnStaticMethod: anyOf(bool(), arrayOf(bool())) + switchConditionsMatchingType: anyOf(bool(), arrayOf(bool())) + noVariableVariables: anyOf(bool(), arrayOf(bool())) + strictArrayFilter: anyOf(bool(), arrayOf(bool())) + illegalConstructorMethodCall: anyOf(bool(), arrayOf(bool())) + ]) + +conditionalTags: + PHPStan\Rules\DisallowedConstructs\DisallowedLooseComparisonRule: + phpstan.rules.rule: %strictRules.disallowedLooseComparison% + PHPStan\Rules\BooleansInConditions\BooleanInBooleanAndRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInDoWhileConditionRule: + phpstan.rules.rule: %strictRules.booleansInLoopConditions% + PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule: + phpstan.rules.rule: %strictRules.booleansInConditions% + PHPStan\Rules\BooleansInConditions\BooleanInWhileConditionRule: + phpstan.rules.rule: %strictRules.booleansInLoopConditions% + PHPStan\Rules\Cast\UselessCastRule: + phpstan.rules.rule: %strictRules.uselessCast% + PHPStan\Rules\Classes\RequireParentConstructCallRule: + phpstan.rules.rule: %strictRules.requireParentConstructorCall% + PHPStan\Rules\DisallowedConstructs\DisallowedBacktickRule: + phpstan.rules.rule: %strictRules.disallowedBacktick% + PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule: + phpstan.rules.rule: %strictRules.disallowedEmpty% + PHPStan\Rules\DisallowedConstructs\DisallowedImplicitArrayCreationRule: + phpstan.rules.rule: %strictRules.disallowedImplicitArrayCreation% + PHPStan\Rules\DisallowedConstructs\DisallowedShortTernaryRule: + phpstan.rules.rule: %strictRules.disallowedShortTernary% + PHPStan\Rules\ForeachLoop\OverwriteVariablesWithForeachRule: + phpstan.rules.rule: %strictRules.overwriteVariablesWithLoop% + PHPStan\Rules\ForLoop\OverwriteVariablesWithForLoopInitRule: + phpstan.rules.rule: %strictRules.overwriteVariablesWithLoop% + PHPStan\Rules\Functions\ArrayFilterStrictRule: + phpstan.rules.rule: %strictRules.strictArrayFilter% + PHPStan\Rules\Functions\ClosureUsesThisRule: + phpstan.rules.rule: %strictRules.closureUsesThis% + PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule: + phpstan.rules.rule: %strictRules.matchingInheritedMethodNames% + PHPStan\Rules\Operators\OperandInArithmeticPostDecrementRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandInArithmeticPostIncrementRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandInArithmeticPreDecrementRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule: + phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%] + PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule: + phpstan.rules.rule: [%strictRules.numericOperandsInArithmeticOperators%, %featureToggles.bleedingEdge%] + PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandsInArithmeticDivisionRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandsInArithmeticExponentiationRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandsInArithmeticModuloRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandsInArithmeticMultiplicationRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\Operators\OperandsInArithmeticSubtractionRule: + phpstan.rules.rule: %strictRules.numericOperandsInArithmeticOperators% + PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule: + phpstan.rules.rule: %strictRules.dynamicCallOnStaticMethod% + PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsCallableRule: + phpstan.rules.rule: %strictRules.dynamicCallOnStaticMethod% + PHPStan\Rules\StrictCalls\StrictFunctionCallsRule: + phpstan.rules.rule: %strictRules.strictFunctionCalls% + PHPStan\Rules\SwitchConditions\MatchingTypeInSwitchCaseConditionRule: + phpstan.rules.rule: %strictRules.switchConditionsMatchingType% + PHPStan\Rules\VariableVariables\VariableMethodCallRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariableMethodCallableRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariableStaticMethodCallRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariableStaticMethodCallableRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariableStaticPropertyFetchRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariableVariablesRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\VariableVariables\VariablePropertyFetchRule: + phpstan.rules.rule: %strictRules.noVariableVariables% + PHPStan\Rules\Methods\IllegalConstructorMethodCallRule: + phpstan.rules.rule: %strictRules.illegalConstructorMethodCall% + PHPStan\Rules\Methods\IllegalConstructorStaticCallRule: + phpstan.rules.rule: %strictRules.illegalConstructorMethodCall% + +services: + - + class: PHPStan\Rules\BooleansInConditions\BooleanRuleHelper + + - + class: PHPStan\Rules\Operators\OperatorRuleHelper + + - + class: PHPStan\Rules\VariableVariables\VariablePropertyFetchRule + arguments: + universalObjectCratesClasses: %universalObjectCratesClasses% + + - + class: PHPStan\Rules\DisallowedConstructs\DisallowedLooseComparisonRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanAndRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanNotRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInBooleanOrRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInDoWhileConditionRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInElseIfConditionRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInIfConditionRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInTernaryOperatorRule + + - + class: PHPStan\Rules\BooleansInConditions\BooleanInWhileConditionRule + + - + class: PHPStan\Rules\Cast\UselessCastRule + arguments: + treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% + treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% + + - + class: PHPStan\Rules\Classes\RequireParentConstructCallRule + + - + class: PHPStan\Rules\DisallowedConstructs\DisallowedBacktickRule + + - + class: PHPStan\Rules\DisallowedConstructs\DisallowedEmptyRule + + - + class: PHPStan\Rules\DisallowedConstructs\DisallowedImplicitArrayCreationRule + + - + class: PHPStan\Rules\DisallowedConstructs\DisallowedShortTernaryRule + + - + class: PHPStan\Rules\ForeachLoop\OverwriteVariablesWithForeachRule + + - + class: PHPStan\Rules\ForLoop\OverwriteVariablesWithForLoopInitRule + + - + class: PHPStan\Rules\Functions\ArrayFilterStrictRule + arguments: + treatPhpDocTypesAsCertain: %treatPhpDocTypesAsCertain% + checkNullables: %checkNullables% + treatPhpDocTypesAsCertainTip: %tips.treatPhpDocTypesAsCertain% + + - + class: PHPStan\Rules\Functions\ClosureUsesThisRule + + - + class: PHPStan\Rules\Methods\WrongCaseOfInheritedMethodRule + + - + class: PHPStan\Rules\Methods\IllegalConstructorMethodCallRule + + - + class: PHPStan\Rules\Methods\IllegalConstructorStaticCallRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticPostDecrementRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticPostIncrementRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticPreDecrementRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticPreIncrementRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticUnaryMinusRule + + - + class: PHPStan\Rules\Operators\OperandInArithmeticUnaryPlusRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticAdditionRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticDivisionRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticExponentiationRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticModuloRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticMultiplicationRule + + - + class: PHPStan\Rules\Operators\OperandsInArithmeticSubtractionRule + + - + class: PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsRule + + - + class: PHPStan\Rules\StrictCalls\DynamicCallOnStaticMethodsCallableRule + + - + class: PHPStan\Rules\StrictCalls\StrictFunctionCallsRule + + - + class: PHPStan\Rules\SwitchConditions\MatchingTypeInSwitchCaseConditionRule + + - + class: PHPStan\Rules\VariableVariables\VariableMethodCallRule + + - + class: PHPStan\Rules\VariableVariables\VariableMethodCallableRule + + - + class: PHPStan\Rules\VariableVariables\VariableStaticMethodCallRule + + - + class: PHPStan\Rules\VariableVariables\VariableStaticMethodCallableRule + + - + class: PHPStan\Rules\VariableVariables\VariableStaticPropertyFetchRule + + - + class: PHPStan\Rules\VariableVariables\VariableVariablesRule diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php new file mode 100644 index 00000000000..eed19aeac0e --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanAndRule.php @@ -0,0 +1,59 @@ + + */ +class BooleanInBooleanAndRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return BooleanAndNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $originalNode = $node->getOriginalNode(); + $messages = []; + $nodeText = $originalNode->getOperatorSigil(); + $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanAnd ? 'booleanAnd' : 'logicalAnd'; + if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { + $leftType = $scope->getType($originalNode->left); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the left side.', + $nodeText, + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier(sprintf('%s.leftNotBoolean', $identifierType))->build(); + } + + $rightScope = $node->getRightScope(); + if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { + $rightType = $rightScope->getType($originalNode->right); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the right side.', + $nodeText, + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier(sprintf('%s.rightNotBoolean', $identifierType))->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php new file mode 100644 index 00000000000..5187cf57bdf --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanNotRule.php @@ -0,0 +1,47 @@ + + */ +class BooleanInBooleanNotRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return BooleanNot::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($this->helper->passesAsBoolean($scope, $node->expr)) { + return []; + } + + $expressionType = $scope->getType($node->expr); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in a negated boolean, %s given.', + $expressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('booleanNot.exprNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php new file mode 100644 index 00000000000..cb06a34162d --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInBooleanOrRule.php @@ -0,0 +1,59 @@ + + */ +class BooleanInBooleanOrRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return BooleanOrNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $originalNode = $node->getOriginalNode(); + $messages = []; + $nodeText = $originalNode->getOperatorSigil(); + $identifierType = $originalNode instanceof Node\Expr\BinaryOp\BooleanOr ? 'booleanOr' : 'logicalOr'; + if (!$this->helper->passesAsBoolean($scope, $originalNode->left)) { + $leftType = $scope->getType($originalNode->left); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the left side.', + $nodeText, + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier(sprintf('%s.leftNotBoolean', $identifierType))->build(); + } + + $rightScope = $node->getRightScope(); + if (!$this->helper->passesAsBoolean($rightScope, $originalNode->right)) { + $rightType = $rightScope->getType($originalNode->right); + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in %s, %s given on the right side.', + $nodeText, + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier(sprintf('%s.rightNotBoolean', $identifierType))->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInDoWhileConditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInDoWhileConditionRule.php new file mode 100644 index 00000000000..d0db29629c0 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInDoWhileConditionRule.php @@ -0,0 +1,46 @@ + + */ +class BooleanInDoWhileConditionRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Node\Stmt\Do_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($this->helper->passesAsBoolean($scope, $node->cond)) { + return []; + } + + $conditionExpressionType = $scope->getType($node->cond); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in a do-while condition, %s given.', + $conditionExpressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('doWhile.condNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php new file mode 100644 index 00000000000..550e9857da3 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInElseIfConditionRule.php @@ -0,0 +1,47 @@ + + */ +class BooleanInElseIfConditionRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return ElseIf_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($this->helper->passesAsBoolean($scope, $node->cond)) { + return []; + } + + $conditionExpressionType = $scope->getType($node->cond); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in an elseif condition, %s given.', + $conditionExpressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('elseif.condNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php new file mode 100644 index 00000000000..5c08894b4eb --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInIfConditionRule.php @@ -0,0 +1,47 @@ + + */ +class BooleanInIfConditionRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return If_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($this->helper->passesAsBoolean($scope, $node->cond)) { + return []; + } + + $conditionExpressionType = $scope->getType($node->cond); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in an if condition, %s given.', + $conditionExpressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('if.condNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php new file mode 100644 index 00000000000..4fe855a5ce0 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInTernaryOperatorRule.php @@ -0,0 +1,51 @@ + + */ +class BooleanInTernaryOperatorRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Ternary::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->if === null) { + return []; // elvis ?: + } + + if ($this->helper->passesAsBoolean($scope, $node->cond)) { + return []; + } + + $conditionExpressionType = $scope->getType($node->cond); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in a ternary operator condition, %s given.', + $conditionExpressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('ternary.condNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInWhileConditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInWhileConditionRule.php new file mode 100644 index 00000000000..2f1661a63fa --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanInWhileConditionRule.php @@ -0,0 +1,46 @@ + + */ +class BooleanInWhileConditionRule implements Rule +{ + + private BooleanRuleHelper $helper; + + public function __construct(BooleanRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Node\Stmt\While_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($this->helper->passesAsBoolean($scope, $node->cond)) { + return []; + } + + $conditionExpressionType = $scope->getType($node->cond); + + return [ + RuleErrorBuilder::message(sprintf( + 'Only booleans are allowed in a while condition, %s given.', + $conditionExpressionType->describe(VerbosityLevel::typeOnly()), + ))->identifier('while.condNotBoolean')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanRuleHelper.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanRuleHelper.php new file mode 100644 index 00000000000..4ecba329926 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/BooleansInConditions/BooleanRuleHelper.php @@ -0,0 +1,42 @@ +ruleLevelHelper = $ruleLevelHelper; + } + + public function passesAsBoolean(Scope $scope, Expr $expr): bool + { + $type = $scope->getType($expr); + if ($type instanceof MixedType) { + return !$type->isExplicitMixed(); + } + $typeToCheck = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $type): bool => $type->isBoolean()->yes(), + ); + $foundType = $typeToCheck->getType(); + if ($foundType instanceof ErrorType) { + return true; + } + + return $foundType->isBoolean()->yes(); + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Cast/UselessCastRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Cast/UselessCastRule.php new file mode 100644 index 00000000000..662975055aa --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Cast/UselessCastRule.php @@ -0,0 +1,81 @@ + + */ +class UselessCastRule implements Rule +{ + + private bool $treatPhpDocTypesAsCertain; + + private bool $treatPhpDocTypesAsCertainTip; + + public function __construct( + bool $treatPhpDocTypesAsCertain, + bool $treatPhpDocTypesAsCertainTip + ) + { + $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; + $this->treatPhpDocTypesAsCertainTip = $treatPhpDocTypesAsCertainTip; + } + + public function getNodeType(): string + { + return Cast::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $castType = $scope->getType($node); + if ($castType instanceof ErrorType) { + return []; + } + $castType = $castType->generalize(GeneralizePrecision::lessSpecific()); + + if ($this->treatPhpDocTypesAsCertain) { + $expressionType = $scope->getType($node->expr); + } else { + $expressionType = $scope->getNativeType($node->expr); + } + if ($castType->isSuperTypeOf($expressionType)->yes()) { + $addTip = function (RuleErrorBuilder $ruleErrorBuilder) use ($scope, $node, $castType): RuleErrorBuilder { + if (!$this->treatPhpDocTypesAsCertain) { + return $ruleErrorBuilder; + } + + if (!$this->treatPhpDocTypesAsCertainTip) { + return $ruleErrorBuilder; + } + + $expressionTypeWithoutPhpDoc = $scope->getNativeType($node->expr); + if ($castType->isSuperTypeOf($expressionTypeWithoutPhpDoc)->yes()) { + return $ruleErrorBuilder; + } + + return $ruleErrorBuilder->treatPhpDocTypesAsCertainTip(); + }; + return [ + $addTip(RuleErrorBuilder::message(sprintf( + 'Casting to %s something that\'s already %s.', + $castType->describe(VerbosityLevel::typeOnly()), + $expressionType->describe(VerbosityLevel::typeOnly()), + )))->identifier('cast.useless')->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Classes/RequireParentConstructCallRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Classes/RequireParentConstructCallRule.php new file mode 100644 index 00000000000..38c5e0339dc --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Classes/RequireParentConstructCallRule.php @@ -0,0 +1,143 @@ + + */ +class RequireParentConstructCallRule implements Rule +{ + + public function getNodeType(): string + { + return ClassMethod::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$scope->isInClass()) { + throw new ShouldNotHappenException(); + } + + if ($scope->isInTrait()) { + return []; + } + + if ($node->name->name !== '__construct') { + return []; + } + + if ($node->isAbstract()) { + return []; + } + + $classReflection = $scope->getClassReflection()->getNativeReflection(); + if ($classReflection->isInterface() || $classReflection->isAnonymous()) { + return []; + } + + if ($this->callsParentConstruct($node)) { + return []; + } + + $parentClass = $this->getParentConstructorClass($classReflection); + if ($parentClass !== false) { + return [ + RuleErrorBuilder::message(sprintf( + '%s::__construct() does not call parent constructor from %s.', + $classReflection->getName(), + $parentClass->getName(), + ))->identifier('constructor.missingParentCall')->build(), + ]; + } + + return []; + } + + private function callsParentConstruct(Node $parserNode): bool + { + if (!property_exists($parserNode, 'stmts')) { + return false; + } + + foreach ($parserNode->stmts as $statement) { + if ($statement instanceof Node\Stmt\Expression) { + $statement = $statement->expr; + } + + $statement = $this->ignoreErrorSuppression($statement); + if ($statement instanceof StaticCall) { + if ( + $statement->class instanceof Name + && ((string) $statement->class === 'parent') + && $statement->name instanceof Node\Identifier + && $statement->name->name === '__construct' + ) { + return true; + } + } else { + if ($this->callsParentConstruct($statement)) { + return true; + } + } + } + + return false; + } + + /** + * @param ReflectionClass|ReflectionEnum $classReflection + * @return ReflectionClass|false + */ + private function getParentConstructorClass($classReflection) + { + $parentClass = $classReflection->getParentClass(); + while ($parentClass !== false) { + $constructor = $parentClass->hasMethod('__construct') ? $parentClass->getMethod('__construct') : null; + $constructorWithClassName = $parentClass->hasMethod($parentClass->getName()) ? $parentClass->getMethod($parentClass->getName()) : null; + if ( + ( + $constructor !== null + && $constructor->getDeclaringClass()->getName() === $parentClass->getName() + && !$constructor->isAbstract() + && !$constructor->isPrivate() + && !$constructor->isDeprecated() + ) || ( + $constructorWithClassName !== null + && $constructorWithClassName->getDeclaringClass()->getName() === $parentClass->getName() + && !$constructorWithClassName->isAbstract() + ) + ) { + return $parentClass; + } + + $parentClass = $parentClass->getParentClass(); + } + + return false; + } + + private function ignoreErrorSuppression(Node $statement): Node + { + if ($statement instanceof Node\Expr\ErrorSuppress) { + + return $statement->expr; + } + + return $statement; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php new file mode 100644 index 00000000000..76e401ceef5 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedBacktickRule.php @@ -0,0 +1,31 @@ + + */ +class DisallowedBacktickRule implements Rule +{ + + public function getNodeType(): string + { + return ShellExec::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return [ + RuleErrorBuilder::message('Backtick operator is not allowed. Use shell_exec() instead.') + ->identifier('backtick.notAllowed') + ->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php new file mode 100644 index 00000000000..d19f5ea20d2 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedEmptyRule.php @@ -0,0 +1,31 @@ + + */ +class DisallowedEmptyRule implements Rule +{ + + public function getNodeType(): string + { + return Empty_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + return [ + RuleErrorBuilder::message('Construct empty() is not allowed. Use more strict comparison.') + ->identifier('empty.notAllowed') + ->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php new file mode 100644 index 00000000000..cee777ce991 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedImplicitArrayCreationRule.php @@ -0,0 +1,65 @@ + + */ +class DisallowedImplicitArrayCreationRule implements Rule +{ + + public function getNodeType(): string + { + return Assign::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->var instanceof ArrayDimFetch) { + return []; + } + + $node = $node->var; + while ($node instanceof ArrayDimFetch) { + $node = $node->var; + } + + if (!$node instanceof Variable) { + return []; + } + + if (!is_string($node->name)) { + return []; + } + + $certainty = $scope->hasVariableType($node->name); + if ($certainty->no()) { + return [ + RuleErrorBuilder::message(sprintf('Implicit array creation is not allowed - variable $%s does not exist.', $node->name)) + ->identifier('variable.implicitArray') + ->build(), + ]; + } + + if ($certainty->maybe()) { + return [ + RuleErrorBuilder::message(sprintf('Implicit array creation is not allowed - variable $%s might not exist.', $node->name)) + ->identifier('variable.implicitArray') + ->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php new file mode 100644 index 00000000000..70b8514f1b8 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedLooseComparisonRule.php @@ -0,0 +1,48 @@ + + */ +class DisallowedLooseComparisonRule implements Rule +{ + + public function getNodeType(): string + { + return BinaryOp::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof Equal) { + return [ + RuleErrorBuilder::message( + 'Loose comparison via "==" is not allowed.', + )->tip('Use strict comparison via "===" instead.') + ->identifier('equal.notAllowed') + ->build(), + ]; + } + if ($node instanceof NotEqual) { + return [ + RuleErrorBuilder::message( + 'Loose comparison via "!=" is not allowed.', + )->tip('Use strict comparison via "!==" instead.') + ->identifier('notEqual.notAllowed') + ->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php new file mode 100644 index 00000000000..fac42790d15 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/DisallowedConstructs/DisallowedShortTernaryRule.php @@ -0,0 +1,35 @@ + + */ +class DisallowedShortTernaryRule implements Rule +{ + + public function getNodeType(): string + { + return Ternary::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->if !== null) { + return []; + } + + return [ + RuleErrorBuilder::message('Short ternary operator is not allowed. Use null coalesce operator if applicable or consider using long ternary.') + ->identifier('ternary.shortNotAllowed') + ->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php new file mode 100644 index 00000000000..f710474e2f9 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForLoop/OverwriteVariablesWithForLoopInitRule.php @@ -0,0 +1,77 @@ + + */ +class OverwriteVariablesWithForLoopInitRule implements Rule +{ + + public function getNodeType(): string + { + return For_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + foreach ($node->init as $expr) { + if (!($expr instanceof Assign)) { + continue; + } + + foreach ($this->checkValueVar($scope, $expr->var) as $error) { + $errors[] = $error; + } + } + + return $errors; + } + + /** + * @return list + */ + private function checkValueVar(Scope $scope, Expr $expr): array + { + $errors = []; + if ( + $expr instanceof Node\Expr\Variable + && is_string($expr->name) + && $scope->hasVariableType($expr->name)->yes() + ) { + $errors[] = RuleErrorBuilder::message(sprintf('For loop initial assignment overwrites variable $%s.', $expr->name)) + ->identifier('for.variableOverwrite') + ->build(); + } + + if ( + $expr instanceof Node\Expr\List_ + || $expr instanceof Node\Expr\Array_ + ) { + foreach ($expr->items as $item) { + if ($item === null) { + continue; + } + + foreach ($this->checkValueVar($scope, $item->value) as $error) { + $errors[] = $error; + } + } + } + + return $errors; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php new file mode 100644 index 00000000000..0cf620c37ee --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/ForeachLoop/OverwriteVariablesWithForeachRule.php @@ -0,0 +1,80 @@ + + */ +class OverwriteVariablesWithForeachRule implements Rule +{ + + public function getNodeType(): string + { + return Foreach_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $errors = []; + if ( + $node->keyVar instanceof Node\Expr\Variable + && is_string($node->keyVar->name) + && $scope->hasVariableType($node->keyVar->name)->yes() + ) { + $errors[] = RuleErrorBuilder::message(sprintf('Foreach overwrites $%s with its key variable.', $node->keyVar->name)) + ->identifier('foreach.keyOverwrite') + ->build(); + } + + foreach ($this->checkValueVar($scope, $node->valueVar) as $error) { + $errors[] = $error; + } + + return $errors; + } + + /** + * @return list + */ + private function checkValueVar(Scope $scope, Expr $expr): array + { + $errors = []; + if ( + $expr instanceof Node\Expr\Variable + && is_string($expr->name) + && $scope->hasVariableType($expr->name)->yes() + ) { + $errors[] = RuleErrorBuilder::message(sprintf('Foreach overwrites $%s with its value variable.', $expr->name)) + ->identifier('foreach.valueOverwrite') + ->build(); + } + + if ( + $expr instanceof Node\Expr\List_ + || $expr instanceof Node\Expr\Array_ + ) { + foreach ($expr->items as $item) { + if ($item === null) { + continue; + } + + foreach ($this->checkValueVar($scope, $item->value) as $error) { + $errors[] = $error; + } + } + } + + return $errors; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ArrayFilterStrictRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ArrayFilterStrictRule.php new file mode 100644 index 00000000000..6760c7d563e --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ArrayFilterStrictRule.php @@ -0,0 +1,162 @@ + + */ +class ArrayFilterStrictRule implements Rule +{ + + private ReflectionProvider $reflectionProvider; + + private bool $treatPhpDocTypesAsCertain; + + private bool $checkNullables; + + private bool $treatPhpDocTypesAsCertainTip; + + public function __construct( + ReflectionProvider $reflectionProvider, + bool $treatPhpDocTypesAsCertain, + bool $checkNullables, + bool $treatPhpDocTypesAsCertainTip + ) + { + $this->reflectionProvider = $reflectionProvider; + $this->treatPhpDocTypesAsCertain = $treatPhpDocTypesAsCertain; + $this->checkNullables = $checkNullables; + $this->treatPhpDocTypesAsCertainTip = $treatPhpDocTypesAsCertainTip; + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Name) { + return []; + } + + if (!$this->reflectionProvider->hasFunction($node->name, $scope)) { + return []; + } + + $functionReflection = $this->reflectionProvider->getFunction($node->name, $scope); + + if ($functionReflection->getName() !== 'array_filter') { + return []; + } + + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs( + $scope, + $node->getArgs(), + $functionReflection->getVariants(), + $functionReflection->getNamedArgumentsVariants(), + ); + + $normalizedFuncCall = ArgumentsNormalizer::reorderFuncArguments($parametersAcceptor, $node); + + if ($normalizedFuncCall === null) { + return []; + } + + $args = $normalizedFuncCall->getArgs(); + if (count($args) === 0) { + return []; + } + + if (count($args) === 1) { + $arrayType = $scope->getType($args[0]->value); + $itemType = $arrayType->getIterableValueType(); + if ($itemType instanceof UnionType) { + $hasTruthy = false; + $hasFalsey = false; + foreach ($itemType->getTypes() as $innerType) { + $booleanType = $innerType->toBoolean(); + if ($booleanType->isTrue()->yes()) { + $hasTruthy = true; + continue; + } + if ($booleanType->isFalse()->yes()) { + $hasFalsey = true; + continue; + } + + $hasTruthy = false; + $hasFalsey = false; + break; + } + + if ($hasTruthy && $hasFalsey) { + return []; + } + } elseif ($itemType->isBoolean()->yes()) { + return []; + } elseif ($itemType->isArray()->yes()) { + return []; + } + + return [ + RuleErrorBuilder::message('Call to function array_filter() requires parameter #2 to be passed to avoid loose comparison semantics.') + ->identifier('arrayFilter.strict') + ->build(), + ]; + } + + $nativeCallbackType = $scope->getNativeType($args[1]->value); + + if ($this->treatPhpDocTypesAsCertain) { + $callbackType = $scope->getType($args[1]->value); + } else { + $callbackType = $nativeCallbackType; + } + + if ($this->isCallbackTypeNull($callbackType)) { + $message = 'Parameter #2 of array_filter() cannot be null to avoid loose comparison semantics (%s given).'; + $errorBuilder = RuleErrorBuilder::message(sprintf( + $message, + $callbackType->describe(VerbosityLevel::typeOnly()), + ))->identifier('arrayFilter.strict'); + + if ($this->treatPhpDocTypesAsCertainTip && !$this->isCallbackTypeNull($nativeCallbackType) && $this->treatPhpDocTypesAsCertain) { + $errorBuilder->treatPhpDocTypesAsCertainTip(); + } + + return [$errorBuilder->build()]; + } + + return []; + } + + private function isCallbackTypeNull(Type $callbackType): bool + { + if ($callbackType->isNull()->yes()) { + return true; + } + + if ($callbackType->isNull()->no()) { + return false; + } + + return $this->checkNullables; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ClosureUsesThisRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ClosureUsesThisRule.php new file mode 100644 index 00000000000..4f41d26b428 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Functions/ClosureUsesThisRule.php @@ -0,0 +1,52 @@ + + */ +class ClosureUsesThisRule implements Rule +{ + + public function getNodeType(): string + { + return Node\Expr\Closure::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->static) { + return []; + } + + if ($scope->isInClosureBind()) { + return []; + } + + $messages = []; + foreach ($node->uses as $closureUse) { + $varType = $scope->getType($closureUse->var); + if (!is_string($closureUse->var->name)) { + continue; + } + if (!$varType instanceof ThisType) { + continue; + } + + $messages[] = RuleErrorBuilder::message(sprintf('Anonymous function uses $this assigned to variable $%s. Use $this directly in the function body.', $closureUse->var->name)) + ->line($closureUse->getStartLine()) + ->identifier('closure.useThis') + ->build(); + } + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorMethodCallRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorMethodCallRule.php new file mode 100644 index 00000000000..1dba6ed6d24 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorMethodCallRule.php @@ -0,0 +1,34 @@ + + */ +final class IllegalConstructorMethodCallRule implements Rule +{ + + public function getNodeType(): string + { + return Node\Expr\MethodCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Identifier || $node->name->toLowerString() !== '__construct') { + return []; + } + + return [ + RuleErrorBuilder::message('Call to __construct() on an existing object is not allowed.') + ->identifier('constructor.call') + ->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorStaticCallRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorStaticCallRule.php new file mode 100644 index 00000000000..fa747d6a2b5 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/IllegalConstructorStaticCallRule.php @@ -0,0 +1,92 @@ + + */ +final class IllegalConstructorStaticCallRule implements Rule +{ + + public function getNodeType(): string + { + return Node\Expr\StaticCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Identifier || $node->name->toLowerString() !== '__construct') { + return []; + } + + if ($this->isCollectCallingConstructor($node, $scope)) { + return []; + } + + return [ + RuleErrorBuilder::message('Static call to __construct() is only allowed on a parent class in the constructor.') + ->identifier('constructor.call') + ->build(), + ]; + } + + private function isCollectCallingConstructor(Node\Expr\StaticCall $node, Scope $scope): bool + { + // __construct should be called from inside constructor + if ($scope->getFunction() === null) { + return false; + } + + if ($scope->getFunction()->getName() !== '__construct') { + if (!$this->isInRenamedTraitConstructor($scope)) { + return false; + } + } + + if (!$scope->isInClass()) { + return false; + } + + if (!$node->class instanceof Node\Name) { + return false; + } + + $parentClasses = array_map(static fn (string $name) => strtolower($name), $scope->getClassReflection()->getParentClassesNames()); + + return in_array(strtolower($scope->resolveName($node->class)), $parentClasses, true); + } + + private function isInRenamedTraitConstructor(Scope $scope): bool + { + if (!$scope->isInClass()) { + return false; + } + + if (!$scope->isInTrait()) { + return false; + } + + if ($scope->getFunction() === null) { + return false; + } + + $traitAliases = $scope->getClassReflection()->getNativeReflection()->getTraitAliases(); + $functionName = $scope->getFunction()->getName(); + if (!array_key_exists($functionName, $traitAliases)) { + return false; + } + + return $traitAliases[$functionName] === sprintf('%s::%s', $scope->getTraitReflection()->getName(), '__construct'); + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php new file mode 100644 index 00000000000..5f800e50284 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Methods/WrongCaseOfInheritedMethodRule.php @@ -0,0 +1,86 @@ + + */ +class WrongCaseOfInheritedMethodRule implements Rule +{ + + public function getNodeType(): string + { + return InClassMethodNode::class; + } + + public function processNode( + Node $node, + Scope $scope + ): array + { + $methodReflection = $node->getMethodReflection(); + $declaringClass = $methodReflection->getDeclaringClass(); + + $messages = []; + if ($declaringClass->getParentClass() !== null) { + $parentMessage = $this->findMethod( + $declaringClass, + $declaringClass->getParentClass(), + $methodReflection->getName(), + ); + if ($parentMessage !== null) { + $messages[] = $parentMessage; + } + } + + foreach ($declaringClass->getInterfaces() as $interface) { + $interfaceMessage = $this->findMethod( + $declaringClass, + $interface, + $methodReflection->getName(), + ); + if ($interfaceMessage === null) { + continue; + } + + $messages[] = $interfaceMessage; + } + + return $messages; + } + + private function findMethod( + ClassReflection $declaringClass, + ClassReflection $classReflection, + string $methodName + ): ?IdentifierRuleError + { + if (!$classReflection->hasNativeMethod($methodName)) { + return null; + } + + $parentMethod = $classReflection->getNativeMethod($methodName); + if ($parentMethod->getName() === $methodName) { + return null; + } + + return RuleErrorBuilder::message(sprintf( + 'Method %s::%s() does not match %s method name: %s::%s().', + $declaringClass->getDisplayName(), + $methodName, + $classReflection->isInterface() ? 'interface' : 'parent', + $classReflection->getDisplayName(), + $parentMethod->getName(), + ))->identifier('method.nameCase')->build(); + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php new file mode 100644 index 00000000000..4e87a885845 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticIncrementOrDecrementRule.php @@ -0,0 +1,61 @@ + + */ +abstract class OperandInArithmeticIncrementOrDecrementRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + /** + * @param TNodeType $node + */ + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + $varType = $scope->getType($node->var); + + if ( + ($node instanceof PreInc || $node instanceof PostInc) + && !$this->helper->isValidForIncrement($scope, $node->var) + || ($node instanceof PreDec || $node instanceof PostDec) + && !$this->helper->isValidForDecrement($scope, $node->var) + ) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in %s, %s given.', + $this->describeOperation(), + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier(sprintf('%s.nonNumeric', $this->getIdentifier()))->build(); + } + + return $messages; + } + + abstract protected function describeOperation(): string; + + /** + * @return 'preInc'|'postInc'|'preDec'|'postDec' + */ + abstract protected function getIdentifier(): string; + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php new file mode 100644 index 00000000000..d0e08099f6b --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostDecrementRule.php @@ -0,0 +1,28 @@ + + */ +class OperandInArithmeticPostDecrementRule extends OperandInArithmeticIncrementOrDecrementRule +{ + + public function getNodeType(): string + { + return PostDec::class; + } + + protected function describeOperation(): string + { + return 'post-decrement'; + } + + protected function getIdentifier(): string + { + return 'postDec'; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php new file mode 100644 index 00000000000..400d82889a5 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPostIncrementRule.php @@ -0,0 +1,28 @@ + + */ +class OperandInArithmeticPostIncrementRule extends OperandInArithmeticIncrementOrDecrementRule +{ + + public function getNodeType(): string + { + return PostInc::class; + } + + protected function describeOperation(): string + { + return 'post-increment'; + } + + protected function getIdentifier(): string + { + return 'postInc'; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php new file mode 100644 index 00000000000..9d583560077 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreDecrementRule.php @@ -0,0 +1,28 @@ + + */ +class OperandInArithmeticPreDecrementRule extends OperandInArithmeticIncrementOrDecrementRule +{ + + public function getNodeType(): string + { + return PreDec::class; + } + + protected function describeOperation(): string + { + return 'pre-decrement'; + } + + protected function getIdentifier(): string + { + return 'preDec'; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php new file mode 100644 index 00000000000..d5d81f2a51b --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticPreIncrementRule.php @@ -0,0 +1,28 @@ + + */ +class OperandInArithmeticPreIncrementRule extends OperandInArithmeticIncrementOrDecrementRule +{ + + public function getNodeType(): string + { + return PreInc::class; + } + + protected function describeOperation(): string + { + return 'pre-increment'; + } + + protected function getIdentifier(): string + { + return 'preInc'; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php new file mode 100644 index 00000000000..d3db7df519c --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryMinusRule.php @@ -0,0 +1,47 @@ + + */ +class OperandInArithmeticUnaryMinusRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return UnaryMinus::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + + if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) { + $varType = $scope->getType($node->expr); + + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in unary -, %s given.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('unaryMinus.nonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php new file mode 100644 index 00000000000..78313d8c132 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandInArithmeticUnaryPlusRule.php @@ -0,0 +1,47 @@ + + */ +class OperandInArithmeticUnaryPlusRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return UnaryPlus::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + + if (!$this->helper->isValidForArithmeticOperation($scope, $node->expr)) { + $varType = $scope->getType($node->expr); + + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in unary +, %s given.', + $varType->describe(VerbosityLevel::typeOnly()), + ))->identifier('unaryPlus.nonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticAdditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticAdditionRule.php new file mode 100644 index 00000000000..80de1463baa --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticAdditionRule.php @@ -0,0 +1,69 @@ + + */ +class OperandsInArithmeticAdditionRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpPlus) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpPlus) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $leftType = $scope->getType($left); + $rightType = $scope->getType($right); + if (count($leftType->getArrays()) > 0 && count($rightType->getArrays()) > 0) { + return []; + } + + $messages = []; + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in +, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('plus.leftNonNumeric')->build(); + } + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in +, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('plus.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticDivisionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticDivisionRule.php new file mode 100644 index 00000000000..e95b3d624d5 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticDivisionRule.php @@ -0,0 +1,65 @@ + + */ +class OperandsInArithmeticDivisionRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpDiv) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpDiv) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $messages = []; + $leftType = $scope->getType($left); + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in /, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('div.leftNonNumeric')->build(); + } + + $rightType = $scope->getType($right); + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in /, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('div.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php new file mode 100644 index 00000000000..1992b84a7b0 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticExponentiationRule.php @@ -0,0 +1,65 @@ + + */ +class OperandsInArithmeticExponentiationRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpPow) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpPow) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $messages = []; + $leftType = $scope->getType($left); + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in **, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('pow.leftNonNumeric')->build(); + } + + $rightType = $scope->getType($right); + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in **, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('pow.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticModuloRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticModuloRule.php new file mode 100644 index 00000000000..5b5f3c32679 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticModuloRule.php @@ -0,0 +1,65 @@ + + */ +class OperandsInArithmeticModuloRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpMod) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpMod) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $messages = []; + $leftType = $scope->getType($left); + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in %%, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('mod.leftNonNumeric')->build(); + } + + $rightType = $scope->getType($right); + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in %%, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('mod.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php new file mode 100644 index 00000000000..353df4c67d7 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticMultiplicationRule.php @@ -0,0 +1,65 @@ + + */ +class OperandsInArithmeticMultiplicationRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpMul) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpMul) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $messages = []; + $leftType = $scope->getType($left); + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in *, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('mul.leftNonNumeric')->build(); + } + + $rightType = $scope->getType($right); + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in *, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('mul.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php new file mode 100644 index 00000000000..5559d60fe08 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperandsInArithmeticSubtractionRule.php @@ -0,0 +1,65 @@ + + */ +class OperandsInArithmeticSubtractionRule implements Rule +{ + + private OperatorRuleHelper $helper; + + public function __construct(OperatorRuleHelper $helper) + { + $this->helper = $helper; + } + + public function getNodeType(): string + { + return Expr::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node instanceof BinaryOpMinus) { + $left = $node->left; + $right = $node->right; + } elseif ($node instanceof AssignOpMinus) { + $left = $node->var; + $right = $node->expr; + } else { + return []; + } + + $messages = []; + $leftType = $scope->getType($left); + if (!$this->helper->isValidForArithmeticOperation($scope, $left)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in -, %s given on the left side.', + $leftType->describe(VerbosityLevel::typeOnly()), + ))->identifier('minus.leftNonNumeric')->build(); + } + + $rightType = $scope->getType($right); + if (!$this->helper->isValidForArithmeticOperation($scope, $right)) { + $messages[] = RuleErrorBuilder::message(sprintf( + 'Only numeric types are allowed in -, %s given on the right side.', + $rightType->describe(VerbosityLevel::typeOnly()), + ))->identifier('minus.rightNonNumeric')->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperatorRuleHelper.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperatorRuleHelper.php new file mode 100644 index 00000000000..6de54cab150 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/Operators/OperatorRuleHelper.php @@ -0,0 +1,92 @@ +ruleLevelHelper = $ruleLevelHelper; + } + + public function isValidForArithmeticOperation(Scope $scope, Expr $expr): bool + { + $type = $scope->getType($expr); + if ($type instanceof MixedType) { + return true; + } + + // already reported by PHPStan core + if ($type->toNumber() instanceof ErrorType) { + return true; + } + + return $this->isSubtypeOfNumber($scope, $expr); + } + + public function isValidForIncrement(Scope $scope, Expr $expr): bool + { + $type = $scope->getType($expr); + if ($type instanceof MixedType) { + return true; + } + + if ($type->isString()->yes()) { + // Because `$a = 'a'; $a++;` is valid + return true; + } + + return $this->isSubtypeOfNumber($scope, $expr); + } + + public function isValidForDecrement(Scope $scope, Expr $expr): bool + { + $type = $scope->getType($expr); + if ($type instanceof MixedType) { + return true; + } + + return $this->isSubtypeOfNumber($scope, $expr); + } + + private function isSubtypeOfNumber(Scope $scope, Expr $expr): bool + { + $acceptedType = new UnionType([new IntegerType(), new FloatType(), new IntersectionType([new StringType(), new AccessoryNumericStringType()])]); + + $type = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $expr, + '', + static fn (Type $type): bool => $acceptedType->isSuperTypeOf($type)->yes(), + )->getType(); + + if ($type instanceof ErrorType) { + return true; + } + + $isSuperType = $acceptedType->isSuperTypeOf($type); + if ($type instanceof BenevolentUnionType) { + return !$isSuperType->no(); + } + + return $isSuperType->yes(); + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php new file mode 100644 index 00000000000..492aa604c42 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsCallableRule.php @@ -0,0 +1,65 @@ + + */ +class DynamicCallOnStaticMethodsCallableRule implements Rule +{ + + private RuleLevelHelper $ruleLevelHelper; + + public function __construct(RuleLevelHelper $ruleLevelHelper) + { + $this->ruleLevelHelper = $ruleLevelHelper; + } + + public function getNodeType(): string + { + return MethodCallableNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->getName() instanceof Node\Identifier) { + return []; + } + + $name = $node->getName()->name; + $type = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->getVar(), + '', + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($name)->yes(), + )->getType(); + + if ($type instanceof ErrorType || !$type->canCallMethods()->yes() || !$type->hasMethod($name)->yes()) { + return []; + } + + $methodReflection = $type->getMethod($name, $scope); + if ($methodReflection->isStatic()) { + return [ + RuleErrorBuilder::message(sprintf( + 'Dynamic call to static method %s::%s().', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + ))->identifier('staticMethod.dynamicCall')->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php new file mode 100644 index 00000000000..c0ae18b34cc --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/DynamicCallOnStaticMethodsRule.php @@ -0,0 +1,76 @@ + + */ +class DynamicCallOnStaticMethodsRule implements Rule +{ + + private RuleLevelHelper $ruleLevelHelper; + + public function __construct(RuleLevelHelper $ruleLevelHelper) + { + $this->ruleLevelHelper = $ruleLevelHelper; + } + + public function getNodeType(): string + { + return MethodCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Node\Identifier) { + return []; + } + + $name = $node->name->name; + $type = $this->ruleLevelHelper->findTypeToCheck( + $scope, + $node->var, + '', + static fn (Type $type): bool => $type->canCallMethods()->yes() && $type->hasMethod($name)->yes(), + )->getType(); + + if ($type instanceof ErrorType || !$type->canCallMethods()->yes() || !$type->hasMethod($name)->yes()) { + return []; + } + + $methodReflection = $type->getMethod($name, $scope); + if ($methodReflection->isStatic()) { + $prototype = $methodReflection->getPrototype(); + if (in_array($prototype->getDeclaringClass()->getName(), [ + TypeInferenceTestCase::class, + PHPStanTestCase::class, + ], true)) { + return []; + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Dynamic call to static method %s::%s().', + $methodReflection->getDeclaringClass()->getDisplayName(), + $methodReflection->getName(), + ))->identifier('staticMethod.dynamicCall')->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/StrictFunctionCallsRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/StrictFunctionCallsRule.php new file mode 100644 index 00000000000..f959fc91306 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/StrictCalls/StrictFunctionCallsRule.php @@ -0,0 +1,96 @@ + + */ +class StrictFunctionCallsRule implements Rule +{ + + /** @var int[] */ + private array $functionArguments = [ + 'in_array' => 2, + 'array_search' => 2, + 'base64_decode' => 1, + 'array_keys' => 2, + ]; + + private ReflectionProvider $reflectionProvider; + + public function __construct(ReflectionProvider $reflectionProvider) + { + $this->reflectionProvider = $reflectionProvider; + } + + public function getNodeType(): string + { + return FuncCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (!$node->name instanceof Name) { + return []; + } + + if (!$this->reflectionProvider->hasFunction($node->name, $scope)) { + return []; + } + + $function = $this->reflectionProvider->getFunction($node->name, $scope); + $parametersAcceptor = ParametersAcceptorSelector::selectFromArgs($scope, $node->getArgs(), $function->getVariants()); + $node = ArgumentsNormalizer::reorderFuncArguments($parametersAcceptor, $node); + if ($node === null) { + return []; + } + $functionName = strtolower($function->getName()); + if (!array_key_exists($functionName, $this->functionArguments)) { + return []; + } + + if ($functionName === 'array_keys' && !array_key_exists(1, $node->getArgs())) { + return []; + } + + $argumentPosition = $this->functionArguments[$functionName]; + if (!array_key_exists($argumentPosition, $node->getArgs())) { + return [ + RuleErrorBuilder::message(sprintf( + 'Call to function %s() requires parameter #%d to be set.', + $functionName, + $argumentPosition + 1, + ))->identifier('function.strict')->build(), + ]; + } + + $argumentType = $scope->getType($node->getArgs()[$argumentPosition]->value); + $trueType = new ConstantBooleanType(true); + if (!$trueType->isSuperTypeOf($argumentType)->yes()) { + return [ + RuleErrorBuilder::message(sprintf( + 'Call to function %s() requires parameter #%d to be true.', + $functionName, + $argumentPosition + 1, + ))->identifier('function.strict')->build(), + ]; + } + + return []; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php new file mode 100644 index 00000000000..ba7c92f3a0a --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/SwitchConditions/MatchingTypeInSwitchCaseConditionRule.php @@ -0,0 +1,60 @@ + + */ +class MatchingTypeInSwitchCaseConditionRule implements Rule +{ + + private Printer $printer; + + public function __construct(Printer $printer) + { + $this->printer = $printer; + } + + public function getNodeType(): string + { + return Switch_::class; + } + + public function processNode(Node $node, Scope $scope): array + { + $messages = []; + $conditionType = $scope->getType($node->cond); + foreach ($node->cases as $case) { + if ($case->cond === null) { + continue; + } + + $caseType = $scope->getType($case->cond); + if (!$conditionType->isSuperTypeOf($caseType)->no()) { + continue; + } + + $messages[] = RuleErrorBuilder::message(sprintf( + 'Switch condition type (%s) does not match case condition %s (%s).', + $conditionType->describe(VerbosityLevel::value()), + $this->printer->prettyPrintExpr($case->cond), + $caseType->describe(VerbosityLevel::typeOnly()), + )) + ->line($case->getStartLine()) + ->identifier('switch.type') + ->build(); + } + + return $messages; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallRule.php new file mode 100644 index 00000000000..d55fc7894d0 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallRule.php @@ -0,0 +1,38 @@ + + */ +class VariableMethodCallRule implements Rule +{ + + public function getNodeType(): string + { + return MethodCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->name instanceof Node\Identifier) { + return []; + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable method call on %s.', + $scope->getType($node->var)->describe(VerbosityLevel::typeOnly()), + ))->identifier('method.dynamicName')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallableRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallableRule.php new file mode 100644 index 00000000000..dd891a9e8c5 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableMethodCallableRule.php @@ -0,0 +1,38 @@ + + */ +class VariableMethodCallableRule implements Rule +{ + + public function getNodeType(): string + { + return MethodCallableNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->getName() instanceof Node\Identifier) { + return []; + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable method call on %s.', + $scope->getType($node->getVar())->describe(VerbosityLevel::typeOnly()), + ))->identifier('method.dynamicName')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariablePropertyFetchRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariablePropertyFetchRule.php new file mode 100644 index 00000000000..760bff697e8 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariablePropertyFetchRule.php @@ -0,0 +1,94 @@ + + */ +class VariablePropertyFetchRule implements Rule +{ + + private ReflectionProvider $reflectionProvider; + + /** @var string[] */ + private array $universalObjectCratesClasses; + + /** + * @param string[] $universalObjectCratesClasses + */ + public function __construct(ReflectionProvider $reflectionProvider, array $universalObjectCratesClasses) + { + $this->reflectionProvider = $reflectionProvider; + $this->universalObjectCratesClasses = $universalObjectCratesClasses; + } + + public function getNodeType(): string + { + return PropertyFetch::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->name instanceof Node\Identifier) { + return []; + } + + $fetchedOnType = $scope->getType($node->var); + foreach ($fetchedOnType->getObjectClassNames() as $referencedClass) { + if (!$this->reflectionProvider->hasClass($referencedClass)) { + continue; + } + + $classReflection = $this->reflectionProvider->getClass($referencedClass); + if ( + $this->isUniversalObjectCrate($classReflection) + || $this->isSimpleXMLElement($classReflection) + ) { + return []; + } + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable property access on %s.', + $fetchedOnType->describe(VerbosityLevel::typeOnly()), + ))->identifier('property.dynamicName')->build(), + ]; + } + + private function isSimpleXMLElement( + ClassReflection $classReflection + ): bool + { + return $classReflection->is(SimpleXMLElement::class); + } + + private function isUniversalObjectCrate( + ClassReflection $classReflection + ): bool + { + foreach ($this->universalObjectCratesClasses as $className) { + if (!$this->reflectionProvider->hasClass($className)) { + continue; + } + + if ($classReflection->is($className)) { + return true; + } + } + + return false; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallRule.php new file mode 100644 index 00000000000..963f01d09a2 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallRule.php @@ -0,0 +1,44 @@ + + */ +class VariableStaticMethodCallRule implements Rule +{ + + public function getNodeType(): string + { + return StaticCall::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->name instanceof Node\Identifier) { + return []; + } + + if ($node->class instanceof Node\Name) { + $methodCalledOn = $scope->resolveName($node->class); + } else { + $methodCalledOn = $scope->getType($node->class)->describe(VerbosityLevel::typeOnly()); + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable static method call on %s.', + $methodCalledOn, + ))->identifier('staticMethod.dynamicName')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php new file mode 100644 index 00000000000..2cfebaca86e --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticMethodCallableRule.php @@ -0,0 +1,44 @@ + + */ +class VariableStaticMethodCallableRule implements Rule +{ + + public function getNodeType(): string + { + return StaticMethodCallableNode::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->getName() instanceof Node\Identifier) { + return []; + } + + if ($node->getClass() instanceof Node\Name) { + $methodCalledOn = $scope->resolveName($node->getClass()); + } else { + $methodCalledOn = $scope->getType($node->getClass())->describe(VerbosityLevel::typeOnly()); + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable static method call on %s.', + $methodCalledOn, + ))->identifier('staticMethod.dynamicName')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php new file mode 100644 index 00000000000..bc4759928b3 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableStaticPropertyFetchRule.php @@ -0,0 +1,44 @@ + + */ +class VariableStaticPropertyFetchRule implements Rule +{ + + public function getNodeType(): string + { + return StaticPropertyFetch::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if ($node->name instanceof Node\Identifier) { + return []; + } + + if ($node->class instanceof Node\Name) { + $propertyAccessedOn = $scope->resolveName($node->class); + } else { + $propertyAccessedOn = $scope->getType($node->class)->describe(VerbosityLevel::typeOnly()); + } + + return [ + RuleErrorBuilder::message(sprintf( + 'Variable static property access on %s.', + $propertyAccessedOn, + ))->identifier('staticProperty.dynamicName')->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableVariablesRule.php b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableVariablesRule.php new file mode 100644 index 00000000000..f78e4ef422f --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan-strict-rules/src/Rules/VariableVariables/VariableVariablesRule.php @@ -0,0 +1,36 @@ + + */ +class VariableVariablesRule implements Rule +{ + + public function getNodeType(): string + { + return Variable::class; + } + + public function processNode(Node $node, Scope $scope): array + { + if (is_string($node->name)) { + return []; + } + + return [ + RuleErrorBuilder::message('Variable variables are not allowed.') + ->identifier('variable.dynamicName') + ->build(), + ]; + } + +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan/LICENSE b/tools/.phpstan/vendor/phpstan/phpstan/LICENSE new file mode 100644 index 00000000000..e5f34e607a1 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/LICENSE @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2016 Ondřej Mirtes +Copyright (c) 2025 PHPStan s.r.o. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/.phpstan/vendor/phpstan/phpstan/README.md b/tools/.phpstan/vendor/phpstan/phpstan/README.md new file mode 100644 index 00000000000..689f9841c89 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/README.md @@ -0,0 +1,121 @@ +

    PHPStan - PHP Static Analysis Tool

    + +

    + PHPStan +

    + +

    + Build Status + Latest Stable Version + Total Downloads + License + PHPStan Enabled +

    + +------ + +PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs +even before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of each line of the code +can be checked before you run the actual line. + +**[Read more about PHPStan »](https://phpstan.org/)** + +**[Try out PHPStan on the on-line playground! »](https://phpstan.org/try)** + +## Sponsors + +Want your logo here? [Learn more »](https://phpstan.org/sponsor) + +### Gold Sponsors + +Matt Mullenweg +    +Mojam +
    +CHECK24 + +

    + +### Silver Sponsors + +ShipMonk +Shopware + +

    + +### Bronze Sponsors + +TheCodingMachine +    +Private Packagist +
    +CDN77 +    +Blackfire.io +
    +iO +    +Fame Helsinki +
    +Belsimpel +    +Togetter +
    +RightCapital +    +Shoptet +
    +ZOL +    +EdgeNext +
    +Route4Me: Route Optimizer and Route Planner Software +    +Craft CMS +
    +TicketSwap +    +campoint AG +
    +Crisp.nl +    +Inviqa +
    + + + +[**You can sponsor my open-source work on PHPStan through GitHub Sponsors and also directly.**](https://phpstan.org/sponsor) + +One-time donations [through Revolut.me](https://revolut.me/ondrejmirtes) are also accepted. To request an invoice, [contact me](mailto:ondrej@mirtes.cz) through e-mail. + +## Documentation + +All the documentation lives on the [phpstan.org website](https://phpstan.org/): + +* [Getting Started & User Guide](https://phpstan.org/user-guide/getting-started) +* [Config Reference](https://phpstan.org/config-reference) +* [PHPDocs Basics](https://phpstan.org/writing-php-code/phpdocs-basics) & [PHPDoc Types](https://phpstan.org/writing-php-code/phpdoc-types) +* [Extension Library](https://phpstan.org/user-guide/extension-library) +* [Developing Extensions](https://phpstan.org/developing-extensions/extension-types) +* [API Reference](https://apiref.phpstan.org/) + +## PHPStan Pro + +PHPStan Pro is a paid add-on on top of open-source PHPStan Static Analysis Tool with these premium features: + +* Web UI for browsing found errors, you can click and open your editor of choice on the offending line. +* Continuous analysis (watch mode): scans changed files in the background, refreshes the UI automatically. + +Try it on PHPStan 0.12.45 or later by running it with the `--pro` option. You can create an account either by following the on-screen instructions, or by visiting [account.phpstan.com](https://account.phpstan.com/). + +After 30-day free trial period it costs 7 EUR for individuals monthly, 70 EUR for teams (up to 25 members). By paying for PHPStan Pro, you're supporting the development of open-source PHPStan. + +You can read more about it on [PHPStan's website](https://phpstan.org/blog/introducing-phpstan-pro). + +## Code of Conduct + +This project adheres to a [Contributor Code of Conduct](https://github.com/phpstan/phpstan/blob/master/CODE_OF_CONDUCT.md). By participating in this project and its community, you are expected to uphold this code. + +## Contributing + +Any contributions are welcome. PHPStan's source code open to pull requests lives at [`phpstan/phpstan-src`](https://github.com/phpstan/phpstan-src). diff --git a/tools/.phpstan/vendor/phpstan/phpstan/UPGRADING.md b/tools/.phpstan/vendor/phpstan/phpstan/UPGRADING.md new file mode 100644 index 00000000000..52294909653 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/UPGRADING.md @@ -0,0 +1,338 @@ +Upgrading from PHPStan 1.x to 2.0 +================================= + +## PHP version requirements + +PHPStan now requires PHP 7.4 or newer to run. + +## Upgrading guide for end users + +The best way to get ready for upgrade to PHPStan 2.0 is to update to the **latest PHPStan 1.12 release** +and enable [**Bleeding Edge**](https://phpstan.org/blog/what-is-bleeding-edge). This will enable the new rules and behaviours that 2.0 turns on for all users. + +Also make sure to install and enable [`phpstan/phpstan-deprecation-rules`](https://github.com/phpstan/phpstan-deprecation-rules). + +Once you get to a green build with no deprecations showed on latest PHPStan 1.12.x with Bleeding Edge enabled, you can update all your related PHPStan dependencies to 2.0 in `composer.json`: + +```json +"require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0", + "phpstan/phpstan-doctrine": "^2.0", + "phpstan/phpstan-nette": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", + "phpstan/phpstan-symfony": "^2.0", + "phpstan/phpstan-webmozart-assert": "^2.0", + ... +} +``` + +Don't forget to update [3rd party PHPStan extensions](https://phpstan.org/user-guide/extension-library) as well. + +After changing your `composer.json`, run `composer update 'phpstan/*' -W`. + +It's up to you whether you go through the new reported errors or if you just put them all to the [baseline](https://phpstan.org/user-guide/baseline) ;) Everyone who's on PHPStan 1.12 should be able to upgrade to PHPStan 2.0. + +### Noteworthy changes to code analysis + +* [**Enhancements in handling parameters passed by reference**](https://phpstan.org/blog/enhancements-in-handling-parameters-passed-by-reference) +* [**Validate inline PHPDoc `@var` tag type**](https://phpstan.org/blog/phpstan-1-10-comes-with-lie-detector#validate-inline-phpdoc-%40var-tag-type) +* [**List type enforced**](https://phpstan.org/blog/phpstan-1-9-0-with-phpdoc-asserts-list-type#list-type) +* **Always `true` conditions always reported**: previously reported only with phpstan-strict-rules, this is now always reported. + +### Removed option `checkMissingIterableValueType` + +It's strongly recommended to add the missing array typehints. + +If you want to continue ignoring missing typehints from arrays, add `missingType.iterableValue` error identifier to your `ignoreErrors`: + +```neon +parameters: + ignoreErrors: + - + identifier: missingType.iterableValue +``` + +### Removed option `checkGenericClassInNonGenericObjectType` + +It's strongly recommended to add the missing generic typehints. + +If you want to continue ignoring missing typehints from generics, add `missingType.generics` error identifier to your `ignoreErrors`: + +```neon +parameters: + ignoreErrors: + - + identifier: missingType.generics +``` + +### Removed `checkAlwaysTrue*` options + +These options have been removed because PHPStan now always behaves as if these were set to `true`: + +* `checkAlwaysTrueCheckTypeFunctionCall` +* `checkAlwaysTrueInstanceof` +* `checkAlwaysTrueStrictComparison` +* `checkAlwaysTrueLooseComparison` + +### Removed option `excludes_analyse` + +It has been replaced with [`excludePaths`](https://phpstan.org/user-guide/ignoring-errors#excluding-whole-files). + +### Paths in `excludePaths` and `ignoreErrors` have to be a valid file path or a fnmatch pattern + +If you are excluding a file path that might not exist but you still want to have it in `excludePaths`, append `(?)`: + +```neon +parameters: + excludePaths: + - tests/*/data/* + - src/broken + - node_modules (?) # optional path, might not exist +``` + +If you have the same situation in `ignoreErrors` (ignoring an error in a path that might not exist), use `reportUnmatchedIgnoredErrors: false`. + +```neon +parameters: + reportUnmatchedIgnoredErrors: false +``` + +Appending `(?)` in `ignoreErrors` is not supported. + +### Changes in 1st party PHPStan extensions + +* [phpstan-doctrine](https://github.com/phpstan/phpstan-doctrine) + * Removed config parameter `searchOtherMethodsForQueryBuilderBeginning` (extension now behaves as when this was set to `true`) + * Removed config parameter `queryBuilderFastAlgorithm` (extension now behaves as when this was set to `false`) +* [phpstan-symfony](https://github.com/phpstan/phpstan-symfony) + * Removed legacy options with `_` in the name + * `container_xml_path` -> use `containerXmlPath` + * `constant_hassers` -> use `constantHassers` + * `console_application_loader` -> use `consoleApplicationLoader` + +### Minor backward compatibility breaks + +* Removed unused config parameter `cache.nodesByFileCountMax` +* Removed unused config parameter `memoryLimitFile` +* Removed unused feature toggle `disableRuntimeReflectionProvider` +* Removed unused config parameter `staticReflectionClassNamePatterns` +* Remove `fixerTmpDir` config parameter, use `pro.tmpDir` instead +* Remove `tempResultCachePath` config parameter, use `resultCachePath` instead +* `additionalConfigFiles` config parameter must be a list + +## Upgrading guide for extension developers + +> [!NOTE] +> Please switch to PHPStan 2.0 in a new major version of your extension. It's not feasible to try to support both PHPStan 1.x and PHPStan 2.x with the same extension code. +> +> You can definitely get closer to supporting PHPStan 2.0 without increasing major version by solving reported deprecations and other issues by analysing your extension code with PHPStan & phpstan-deprecation-rules & Bleeding Edge, but the final leap and solving backward incompatibilities should be done by requiring `"phpstan/phpstan": "^2.0"` in your `composer.json`, and releasing a new major version. + +### PHPStan now uses nikic/php-parser v5 + +See [UPGRADING](https://github.com/nikic/PHP-Parser/blob/master/UPGRADE-5.0.md) guide for PHP-Parser. + +The most notable change is how `throw` statement is represented. Previously, `throw` statements like `throw $e;` were represented using the `Stmt\Throw_` class, while uses inside other expressions (such as `$x ?? throw $e`) used the `Expr\Throw_` class. + +Now, `throw $e;` is represented as a `Stmt\Expression` that contains an `Expr\Throw_`. The +`Stmt\Throw_` class has been removed. + +### PHPStan now uses phpstan/phpdoc-parser v2 + +See [UPGRADING](https://github.com/phpstan/phpdoc-parser/blob/2.0.x/UPGRADING.md) guide for phpstan/phpdoc-parser. + +### Returning plain strings as errors no longer supported, use RuleErrorBuilder + +Identifiers are also required in custom rules. + +Learn more: [Using RuleErrorBuilder to enrich reported errors in custom rules](https://phpstan.org/blog/using-rule-error-builder) + +**Before**: + +```php +return ['My error']; +``` + +**After**: + +```php +return [ + RuleErrorBuilder::message('My error') + ->identifier('my.error') + ->build(), +]; +``` + +### Deprecate various `instanceof *Type` in favour of new methods on `Type` interface + +Learn more: [Why Is instanceof *Type Wrong and Getting Deprecated?](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated) + +### Removed deprecated `ParametersAcceptorSelector::selectSingle()` + +Use [`ParametersAcceptorSelector::selectFromArgs()`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ParametersAcceptorSelector.html#_selectFromArgs) instead. It should be used in most places where `selectSingle()` was previously used, like dynamic return type extensions. + +**Before**: + +```php +$defaultReturnType = ParametersAcceptorSelector::selectSingle($functionReflection->getVariants())->getReturnType(); +``` + +**After**: + +```php +$defaultReturnType = ParametersAcceptorSelector::selectFromArgs( + $scope, + $functionCall->getArgs(), + $functionReflection->getVariants() +)->getReturnType(); +``` + +If you're analysing function or method body itself and you're using one of the following methods, ask for `getParameters()` and `getReturnType()` directly on the reflection object: + +* [InClassMethodNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InClassMethodNode.html) +* [InFunctionNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.InFunctionNode.html) +* [FunctionReturnStatementsNode::getFunctionReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.FunctionReturnStatementsNode.html) +* [MethodReturnStatementsNode::getMethodReflection()](https://apiref.phpstan.org/2.0.x/PHPStan.Node.MethodReturnStatementsNode.html) +* [Scope::getFunction()](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.Scope.html#_getFunction) + +**Before**: + +```php +$function = $node->getFunctionReflection(); +$returnType = ParametersAcceptorSelector::selectSingle($function->getVariants())->getReturnType(); +``` + +**After**: + +```php +$returnType = $node->getFunctionReflection()->getReturnType(); +``` + +### Changed `TypeSpecifier::create()` and `SpecifiedTypes` constructor parameters + +[`PHPStan\Analyser\TypeSpecifier::create()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.TypeSpecifier.html#_create) now accepts (all parameters are required): + +* `Expr $expr` +* `Type $type` +* `TypeSpecifierContext $context` +* `Scope $scope` + +If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by this method), call `setAlwaysOverwriteTypes()` and `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::create()`). These methods return a new object (SpecifiedTypes is immutable). + +[`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) constructor now accepts: + +* `array $sureTypes` +* `array $sureNotTypes` + +If you want to change `$overwrite` or `$rootExpr` (previous parameters also used to be accepted by the constructor), call `setAlwaysOverwriteTypes()` and `setRootExpr()`. These methods return a new object (SpecifiedTypes is immutable). + +### `ConstantArrayType` no longer extends `ArrayType` + +`Type::getArrays()` now returns `list`. + +Using `$type instanceof ArrayType` is [being deprecated anyway](https://phpstan.org/blog/why-is-instanceof-type-wrong-and-getting-deprecated) so the impact of this change should be minimal. + +### Changed `TypeSpecifier::specifyTypesInCondition()` + +This method no longer accepts `Expr $rootExpr`. If you want to change it, call `setRootExpr()` on [`SpecifiedTypes`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.SpecifiedTypes.html) (object returned by `TypeSpecifier::specifyTypesInCondition()`). `setRootExpr()` method returns a new object (SpecifiedTypes is immutable). + +### Node attributes `parent`, `previous`, `next` are no longer available + +Learn more: https://phpstan.org/blog/preprocessing-ast-for-custom-rules + +### Removed config parameter `scopeClass` + +As a replacement you can implement [`PHPStan\Type\ExpressionTypeResolverExtension`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.ExpressionTypeResolverExtension.html) interface instead and register it as a service. + +### Removed `PHPStan\Broker\Broker` + +Use [`PHPStan\Reflection\ReflectionProvider`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ReflectionProvider.html) instead. + +`BrokerAwareExtension` was also removed. Ask for `ReflectionProvider` in the extension constructor instead. + +Instead of `PHPStanTestCase::createBroker()`, call `PHPStanTestCase::createReflectionProvider()`. + +### List type is enabled for everyone + +Removed static methods from `AccessoryArrayListType` class: + +* `isListTypeEnabled()` +* `setListTypeEnabled()` +* `intersectWith()` + +Instead of `AccessoryArrayListType::intersectWith($type)`, do `TypeCombinator::intersect($type, new AccessoryArrayListType())`. + +### Minor backward compatibility breaks + +* Classes that were previously `@final` were made `final` +* Parameter `$callableParameters` of [`MutatingScope::enterAnonymousFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterAnonymousFunction) and [`enterArrowFunction()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.MutatingScope.html#_enterArrowFunction) made required +* Parameter `StatementContext $context` of [`NodeScopeResolver::processStmtNodes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Analyser.NodeScopeResolver.html#_processStmtNodes) made required +* ClassPropertiesNode - remove `$extensions` parameter from [`getUninitializedProperties()`](https://apiref.phpstan.org/2.0.x/PHPStan.Node.ClassPropertiesNode.html#_getUninitializedProperties) +* `Type::getSmallerType()`, `Type::getSmallerOrEqualType()`, `Type::getGreaterType()`, `Type::getGreaterOrEqualType()`, `Type::isSmallerThan()`, `Type::isSmallerThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument. +* `CompoundType::isGreaterThan()`, `CompoundType::isGreaterThanOrEqual()` now require [`PhpVersion`](https://apiref.phpstan.org/2.0.x/PHPStan.Php.PhpVersion.html) as argument. +* Removed `ReflectionProvider::supportsAnonymousClasses()` (all reflection providers support anonymous classes) +* Remove `ArrayType::generalizeKeys()` +* Remove `ArrayType::count()`, use `Type::getArraySize()` instead +* Remove `ArrayType::castToArrayKeyType()`, `Type::toArrayKey()` instead +* Remove `UnionType::pickTypes()`, use `pickFromTypes()` instead +* Remove `RegexArrayShapeMatcher::matchType()`, use `matchExpr()` instead +* Remove unused `PHPStanTestCase::$useStaticReflectionProvider` +* Remove `PHPStanTestCase::getReflectors()`, use `getReflector()` instead +* Remove `ClassReflection::getFileNameWithPhpDocs()`, use `getFileName()` instead +* Remove `AnalysisResult::getInternalErrors()`, use `getInternalErrorObjects()` instead +* Remove `ConstantReflection::getValue()`, use `getValueExpr()` instead. To get `Type` from `Expr`, use `Scope::getType()` or `InitializerExprTypeResolver::getType()` +* Remove `PropertyTag::getType()`, use `getReadableType()` / `getWritableType()` instead +* Remove `GenericTypeVariableResolver`, use [`Type::getTemplateType()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getTemplateType) instead +* Rename `Type::isClassStringType()` to `Type::isClassString()` +* Remove `Scope::isSpecified()`, use `hasExpressionType()` instead +* Remove `ConstantArrayType::isEmpty()`, use `isIterableAtLeastOnce()->no()` instead +* Remove `ConstantArrayType::getNextAutoIndex()` +* Removed methods from `ConstantArrayType` - `getFirst*Type` and `getLast*Type` + * Use `getFirstIterable*Type` and `getLastIterable*Type` instead +* Remove `ConstantArrayType::generalizeToArray()` +* Remove `ConstantArrayType::findTypeAndMethodName()`, use `findTypeAndMethodNames()` instead +* Remove `ConstantArrayType::removeLast()`, use [`Type::popArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_popArray) instead +* Remove `ConstantArrayType::removeFirst()`, use [`Type::shiftArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_shiftArray) instead +* Remove `ConstantArrayType::reverse()`, use [`Type::reverseArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_reverseArray) instead +* Remove `ConstantArrayType::chunk()`, use [`Type::chunkArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_chunkArray) instead +* Remove `ConstantArrayType::slice()`, use [`Type::sliceArray()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_sliceArray) instead +* Made `TypeUtils` thinner by removing methods: + * Remove `TypeUtils::getArrays()` and `getAnyArrays()`, use [`Type::getArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getArrays) instead + * Remove `TypeUtils::getConstantArrays()` and `getOldConstantArrays()`, use [`Type::getConstantArrays()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantArrays) instead + * Remove `TypeUtils::getConstantStrings()`, use [`Type::getConstantStrings()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantStrings) instead + * Remove `TypeUtils::getConstantTypes()` and `getAnyConstantTypes()`, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) or [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize) + * Remove `TypeUtils::generalizeType()`, use [`Type::generalize()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_generalize) instead + * Remove `TypeUtils::getDirectClassNames()`, use [`Type::getObjectClassNames()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getObjectClassNames) instead + * Remove `TypeUtils::getConstantScalars()`, use [`Type::isConstantScalarValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantScalarValue) or [`Type::getConstantScalarTypes()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getConstantScalarTypes) instead + * Remove `TypeUtils::getEnumCaseObjects()`, use [`Type::getEnumCases()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getEnumCases) instead + * Remove `TypeUtils::containsCallable()`, use [`Type::isCallable()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isCallable) instead +* Removed `Scope::doNotTreatPhpDocTypesAsCertain()`, use `getNativeType()` instead +* Parameter `$isList` in `ConstantArrayType` constructor can only be `TrinaryLogic`, no longer `bool` +* Parameter `$nextAutoIndexes` in `ConstantArrayType` constructor can only be `non-empty-list`, no longer `int` +* Remove `ConstantType` interface, use [`Type::isConstantValue()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_isConstantValue) instead +* `acceptsNamedArguments()` in `FunctionReflection`, `ExtendedMethodReflection` and `CallableParametersAcceptor` interfaces returns `TrinaryLogic` instead of `bool` +* Remove `FunctionReflection::isFinal()` +* [`Type::getProperty()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.Type.html#_getProperty) now returns [`ExtendedPropertyReflection`](https://apiref.phpstan.org/2.0.x/PHPStan.Reflection.ExtendedPropertyReflection.html) +* Remove `__set_state()` on objects that should not be serialized in cache +* Parameter `$selfClass` of [`TypehintHelper::decideTypeFromReflection()`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.TypehintHelper.html#_decideTypeFromReflection) no longer accepts `string` +* `LevelsTestCase::dataTopics()` data provider made static +* `PHPStan\Node\Printer\Printer` no longer autowired as `PhpParser\PrettyPrinter\Standard`, use `PHPStan\Node\Printer\Printer` in the typehint +* Remove `Type::acceptsWithReason()`, `Type:accepts()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +* Remove `CompoundType::isAcceptedWithReasonBy()`, `CompoundType::isAcceptedBy()` return type changed from `TrinaryLogic` to [`AcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +Remove `Type::isSuperTypeOfWithReason()`, `Type:isSuperTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* Remove `CompoundType::isSubTypeOfWithReasonBy()`, `CompoundType::isSubTypeOf()` return type changed from `TrinaryLogic` to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* Remove `TemplateType::isValidVarianceWithReason()`, changed `TemplateType::isValidVariance()` return type to [`IsSuperTypeOfResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.IsSuperTypeOfResult.html) +* `RuleLevelHelper::accepts()` return type changed from `bool` to [`RuleLevelHelperAcceptsResult`](https://apiref.phpstan.org/2.0.x/PHPStan.Type.AcceptsResult.html) +* Changes around `ClassConstantReflection` + * Class `ClassConstantReflection` removed from BC promise, renamed to `RealClassConstantReflection` + * Interface `ConstantReflection` renamed to `ClassConstantReflection` + * Added more methods around PHPDoc types and native types to the (new) `ClassConstantReflection` + * Interface `GlobalConstantReflection` renamed to `ConstantReflection` +* Renamed interfaces and classes from `*WithPhpDocs` to `Extended*` + * `ParametersAcceptorWithPhpDocs` -> `ExtendedParametersAcceptor` + * `ParameterReflectionWithPhpDocs` -> `ExtendedParameterReflection` + * `FunctionVariantWithPhpDocs` -> `ExtendedFunctionVariant` +* `ClassPropertyNode::getNativeType()` return type changed from AST node to `Type|null` +* Class `PHPStan\Node\ClassMethod` (accessible from `ClassMethodsNode`) is no longer an AST node + * Call `PHPStan\Node\ClassMethod::getNode()` to access the original AST node diff --git a/tools/.phpstan/vendor/phpstan/phpstan/bootstrap.php b/tools/.phpstan/vendor/phpstan/phpstan/bootstrap.php new file mode 100644 index 00000000000..889755e6008 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/bootstrap.php @@ -0,0 +1,144 @@ +loadClass($class); + + return; + } + if (strpos($class, 'PHPStan\\') !== 0 || strpos($class, 'PHPStan\\PhpDocParser\\') === 0) { + return; + } + + if (!in_array('phar', stream_get_wrappers(), true)) { + throw new \Exception('Phar wrapper is not registered. Please review your php.ini settings.'); + } + + if (!self::$polyfillsLoaded) { + self::$polyfillsLoaded = true; + + if ( + PHP_VERSION_ID < 80000 + && empty($GLOBALS['__composer_autoload_files']['a4a119a56e50fbb293281d9a48007e0e']) + && !class_exists(\Symfony\Polyfill\Php80\Php80::class, false) + ) { + $GLOBALS['__composer_autoload_files']['a4a119a56e50fbb293281d9a48007e0e'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php80/Php80.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php80/bootstrap.php'; + } + + if ( + empty($GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a']) + && !class_exists(\Symfony\Polyfill\Mbstring\Mbstring::class, false) + ) { + $GLOBALS['__composer_autoload_files']['0e6d7bf4a5811bfa5cf40c5ccd6fae6a'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-mbstring/Mbstring.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-mbstring/bootstrap.php'; + } + + if ( + empty($GLOBALS['__composer_autoload_files']['e69f7f6ee287b969198c3c9d6777bd38']) + && !class_exists(\Symfony\Polyfill\Intl\Normalizer\Normalizer::class, false) + ) { + $GLOBALS['__composer_autoload_files']['e69f7f6ee287b969198c3c9d6777bd38'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-normalizer/Normalizer.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-normalizer/bootstrap.php'; + } + + if ( + !extension_loaded('intl') + && empty($GLOBALS['__composer_autoload_files']['8825ede83f2f289127722d4e842cf7e8']) + && !class_exists(\Symfony\Polyfill\Intl\Grapheme\Grapheme::class, false) + ) { + $GLOBALS['__composer_autoload_files']['8825ede83f2f289127722d4e842cf7e8'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-grapheme/Grapheme.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-intl-grapheme/bootstrap.php'; + } + + if ( + PHP_VERSION_ID < 80100 + && empty ($GLOBALS['__composer_autoload_files']['23c18046f52bef3eea034657bafda50f']) + && !class_exists(\Symfony\Polyfill\Php81\Php81::class, false) + ) { + $GLOBALS['__composer_autoload_files']['23c18046f52bef3eea034657bafda50f'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/Php81.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php81/bootstrap.php'; + } + + if ( + PHP_VERSION_ID < 80300 + && empty ($GLOBALS['__composer_autoload_files']['662a729f963d39afe703c9d9b7ab4a8c']) + && !class_exists(\Symfony\Polyfill\Php83\Php83::class, false) + ) { + $GLOBALS['__composer_autoload_files']['662a729f963d39afe703c9d9b7ab4a8c'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php83/Php83.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php83/bootstrap.php'; + } + + if ( + PHP_VERSION_ID < 80400 + && empty ($GLOBALS['__composer_autoload_files']['9d2b9fc6db0f153a0a149fefb182415e']) + && !class_exists(\Symfony\Polyfill\Php83\Php84::class, false) + ) { + $GLOBALS['__composer_autoload_files']['9d2b9fc6db0f153a0a149fefb182415e'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php84/Php84.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php84/bootstrap.php'; + } + + if ( + PHP_VERSION_ID < 80500 + && empty ($GLOBALS['__composer_autoload_files']['606a39d89246991a373564698c2d8383']) + && !class_exists(\Symfony\Polyfill\Php83\Php85::class, false) + ) { + $GLOBALS['__composer_autoload_files']['606a39d89246991a373564698c2d8383'] = true; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php85/Php85.php'; + require_once 'phar://' . __DIR__ . '/phpstan.phar/vendor/symfony/polyfill-php85/bootstrap.php'; + } + } + + $filename = str_replace('\\', DIRECTORY_SEPARATOR, $class); + if (strpos($class, 'PHPStan\\BetterReflection\\') === 0) { + $filename = substr($filename, strlen('PHPStan\\BetterReflection\\')); + $filepath = 'phar://' . __DIR__ . '/phpstan.phar/vendor/ondrejmirtes/better-reflection/src/' . $filename . '.php'; + } else { + $filename = substr($filename, strlen('PHPStan\\')); + $filepath = 'phar://' . __DIR__ . '/phpstan.phar/src/' . $filename . '.php'; + } + + if (!file_exists($filepath)) { + return; + } + + require $filepath; + } +} + +spl_autoload_register([PharAutoloader::class, 'loadClass']); diff --git a/tools/.phpstan/vendor/phpstan/phpstan/composer.json b/tools/.phpstan/vendor/phpstan/phpstan/composer.json new file mode 100644 index 00000000000..8b51d4b7166 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/composer.json @@ -0,0 +1,31 @@ +{ + "name": "phpstan/phpstan", + "description": "PHPStan - PHP Static Analysis Tool", + "license": ["MIT"], + "keywords": ["dev", "static analysis"], + "require": { + "php": "^7.4|^8.0" + }, + "conflict": { + "phpstan/phpstan-shim": "*" + }, + "bin": [ + "phpstan", + "phpstan.phar" + ], + "autoload": { + "files": ["bootstrap.php"] + }, + "source": { + "type": "", + "url": "", + "reference": "" + }, + "support": { + "issues": "https://github.com/phpstan/phpstan/issues", + "forum": "https://github.com/phpstan/phpstan/discussions", + "source": "https://github.com/phpstan/phpstan-src", + "docs": "https://phpstan.org/user-guide/getting-started", + "security": "https://github.com/phpstan/phpstan/security/policy" + } +} diff --git a/tools/.phpstan/vendor/phpstan/phpstan/conf/bleedingEdge.neon b/tools/.phpstan/vendor/phpstan/phpstan/conf/bleedingEdge.neon new file mode 100644 index 00000000000..01fee972d82 --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/conf/bleedingEdge.neon @@ -0,0 +1,2 @@ +includes: + - phar://phpstan.phar/conf/bleedingEdge.neon diff --git a/tools/.phpstan/vendor/phpstan/phpstan/phpstan b/tools/.phpstan/vendor/phpstan/phpstan/phpstan new file mode 100755 index 00000000000..7a08ef4850b --- /dev/null +++ b/tools/.phpstan/vendor/phpstan/phpstan/phpstan @@ -0,0 +1,8 @@ +#!/usr/bin/env php + + +A PHPStan extension, to check and require minimal type coverage of PHP code. + +
    + +The type coverage rate = total count of **defined** type declarations / total count of **possible** type declarations. + +E.g. we have 10 methods, but only 7 have defined return type = 70 % return type coverage. + +--- + +PHPStan uses type declarations to determine the type of variables, properties and other expression. Sometimes it's hard to see what PHPStan errors are the important ones among thousands of others. + +Instead of fixing all PHPStan errors at once, we can start with minimal require type coverage. + +
    + + +## How to increase type coverage? + +Here we have 3 possible type declarations: + +* property, +* param +* and return type + +```php +final class ConferenceFactory +{ + private $talkFactory; + + public function createConference(array $data) + { + $talks = $this->talkFactory->create($data); + + return new Conference($talks); + } +} +``` + +The param type is defined as `array`. + +1 defined / 3 possible = **33.3 % type coverage** + +
    + +Our code quality is only at one-third of its potential. Let's get to 100 %! + +```diff + final class ConferenceFactory + { +- private $talkFactory; ++ private TalkFactory $talkFactory; + +- public function createConference(array $data) ++ public function createConference(array $data): Conference + { + $talks = $this->talkFactory->create($data); + + return new Conference($talks); + } + } +``` + +This technique is very simple to start even on legacy project. Also, you're now aware exactly how high coverage your project has. + +
    + +## Install + +```bash +composer require tomasvotruba/type-coverage --dev +``` + +The package is available on PHP 7.2+. + +
    + +## Usage + +With [PHPStan extension installer](https://github.com/phpstan/extension-installer), everything is ready to run. + +Enable each item on their own: + +```yaml +# phpstan.neon +parameters: + type_coverage: + return: 50 + param: 35.5 + property: 70 + + # since PHP 8.3 + constant: 85 +``` + +
    + +## Measure Strict Declares coverage + +Once you've reached 100 % type coverage, make sure [your code is strict and uses types](https://tomasvotruba.com/blog/how-adding-type-declarations-makes-your-code-dangerous): + +```php + + +## Full Paths only + +If you run PHPStan only on some subpaths that are different from your setup in `phpstan.neon`, e.g.: + +```bash +vendor/bin/phpstan analyze src/Controller +``` + +This package could show false positives, as classes in the `src/Controller` could be slightly less typed. This would be spamming whole PHPStan output and make hard to see any other errors you look for. + +That's why this package only triggers if there are full paths, e.g.: + +```bash +vendor/bin/phpstan +```` + +
    + +Happy coding! diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/composer.json b/tools/.phpstan/vendor/tomasvotruba/type-coverage/composer.json new file mode 100644 index 00000000000..e32de7ffba1 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/composer.json @@ -0,0 +1,24 @@ +{ + "name": "tomasvotruba/type-coverage", + "type": "phpstan-extension", + "description": "Measure type coverage of your project", + "license": "MIT", + "keywords": ["static analysis", "phpstan-extension"], + "require": { + "php": "^7.4 || ^8.0", + "phpstan/phpstan": "^2.0", + "nette/utils": "^3.2 || ^4.0" + }, + "autoload": { + "psr-4": { + "TomasVotruba\\TypeCoverage\\": "src" + } + }, + "extra": { + "phpstan": { + "includes": [ + "config/extension.neon" + ] + } + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/config/extension.neon b/tools/.phpstan/vendor/tomasvotruba/type-coverage/config/extension.neon new file mode 100644 index 00000000000..b2a58b699c2 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/config/extension.neon @@ -0,0 +1,79 @@ +parametersSchema: + # see https://doc.nette.org/en/schema for configuration + type_coverage: structure([ + declare: anyOf(float(), int()) + # type declarations + return_type: anyOf(float(), int()) + param_type: anyOf(float(), int()) + property_type: anyOf(float(), int()) + constant_type: anyOf(float(), int()) + print_suggestions: bool() + # aliases to avoid typos + return: anyOf(schema(float(), nullable()), schema(int(), nullable())) + param: anyOf(schema(float(), nullable()), schema(int(), nullable())) + property: anyOf(schema(float(), nullable()), schema(int(), nullable())) + constant: anyOf(schema(float(), nullable()), schema(int(), nullable())) + + # measure + measure: bool() + ]) + +# default parameters +parameters: + type_coverage: + declare: 0 + # type declarations + return_type: 99 + param_type: 99 + property_type: 99 + constant_type: 99 + # default, yet deprecated + print_suggestions: true + # aliases + return: null + param: null + property: null + constant: null + + measure: false + +services: + - TomasVotruba\TypeCoverage\Formatter\TypeCoverageFormatter + - TomasVotruba\TypeCoverage\CollectorDataNormalizer + + - + factory: TomasVotruba\TypeCoverage\Configuration + arguments: + - %type_coverage% + + # collectors + - + class: TomasVotruba\TypeCoverage\Collectors\ReturnTypeDeclarationCollector + tags: + - phpstan.collector + + - + class: TomasVotruba\TypeCoverage\Collectors\ParamTypeDeclarationCollector + tags: + - phpstan.collector + + - + class: TomasVotruba\TypeCoverage\Collectors\PropertyTypeDeclarationCollector + tags: + - phpstan.collector + - + class: TomasVotruba\TypeCoverage\Collectors\ConstantTypeDeclarationCollector + tags: + - phpstan.collector + + - + class: TomasVotruba\TypeCoverage\Collectors\DeclareCollector + tags: + - phpstan.collector + +rules: + - TomasVotruba\TypeCoverage\Rules\ParamTypeCoverageRule + - TomasVotruba\TypeCoverage\Rules\ReturnTypeCoverageRule + - TomasVotruba\TypeCoverage\Rules\PropertyTypeCoverageRule + - TomasVotruba\TypeCoverage\Rules\ConstantTypeCoverageRule + - TomasVotruba\TypeCoverage\Rules\DeclareCoverageRule diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/CollectorDataNormalizer.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/CollectorDataNormalizer.php new file mode 100644 index 00000000000..e05c09d15fc --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/CollectorDataNormalizer.php @@ -0,0 +1,36 @@ +}>> $collectorDataByPath + */ + public function normalize(array $collectorDataByPath): TypeCountAndMissingTypes + { + $totalCount = 0; + $missingCount = 0; + + $missingTypeLinesByFilePath = []; + + foreach ($collectorDataByPath as $filePath => $typeCoverageData) { + foreach ($typeCoverageData as $nestedData) { + $totalCount += $nestedData[0]; + + $missingCount += count($nestedData[1]); + + $missingTypeLinesByFilePath[$filePath] = array_merge( + $missingTypeLinesByFilePath[$filePath] ?? [], + $nestedData[1] + ); + } + } + + return new TypeCountAndMissingTypes($totalCount, $missingCount, $missingTypeLinesByFilePath); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ConstantTypeDeclarationCollector.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ConstantTypeDeclarationCollector.php new file mode 100644 index 00000000000..b0babdd80df --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ConstantTypeDeclarationCollector.php @@ -0,0 +1,77 @@ + + */ + public function getNodeType(): string + { + return ClassConstantsNode::class; + } + + /** + * @param ClassConstantsNode $node + * @return array)>> + */ + public function processNode(Node $node, Scope $scope): array + { + // enable only on PHP 8.3+ + if (PHP_VERSION_ID < 80300) { + return [0, []]; + } + + $constantCount = count($node->getConstants()); + + $missingTypeLines = []; + + foreach ($node->getConstants() as $classConst) { + // blocked by parent type + if ($this->isGuardedByParentClassConstant($scope, $classConst)) { + continue; + } + + // already typed + if ($classConst->type instanceof Node) { + continue; + } + + // give useful context + $missingTypeLines[] = $classConst->getLine(); + } + + return [$constantCount, $missingTypeLines]; + } + + private function isGuardedByParentClassConstant(Scope $scope, ClassConst $classConst): bool + { + $constName = $classConst->consts[0]->name->toString(); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { + return false; + } + + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->hasConstant($constName)) { + return true; + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/DeclareCollector.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/DeclareCollector.php new file mode 100644 index 00000000000..ad677eeede1 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/DeclareCollector.php @@ -0,0 +1,51 @@ +getNodes() as $node) { + if (! $node instanceof Declare_) { + continue; + } + + foreach ($node->declares as $declare) { + if ( + $declare->key->name !== 'strict_types' + ) { + continue; + } + + if ( + ! $declare->value instanceof LNumber + || $declare->value->value !== 1 + ) { + return false; + } + + return true; + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ParamTypeDeclarationCollector.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ParamTypeDeclarationCollector.php new file mode 100644 index 00000000000..a9d4a494380 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ParamTypeDeclarationCollector.php @@ -0,0 +1,72 @@ +shouldSkipFunctionLike($node)) { + return null; + } + + $missingTypeLines = []; + $paramCount = count($node->getParams()); + + foreach ($node->getParams() as $param) { + if ($param->variadic) { + // skip variadic + --$paramCount; + continue; + } + + if ($param->type === null) { + $missingTypeLines[] = $param->getLine(); + } + } + + return [$paramCount, $missingTypeLines]; + } + + private function shouldSkipFunctionLike(FunctionLike $functionLike): bool + { + // nothing to analyse + if ($functionLike->getParams() === []) { + return true; + } + + return $this->hasFunctionLikeCallableParam($functionLike); + } + + private function hasFunctionLikeCallableParam(FunctionLike $functionLike): bool + { + // skip callable, can be anythings + $docComment = $functionLike->getDocComment(); + if (! $docComment instanceof Doc) { + return false; + } + + $docCommentText = $docComment->getText(); + return strpos($docCommentText, '@param callable') !== false; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/PropertyTypeDeclarationCollector.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/PropertyTypeDeclarationCollector.php new file mode 100644 index 00000000000..86c09ccde65 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/PropertyTypeDeclarationCollector.php @@ -0,0 +1,93 @@ + + */ + public function getNodeType(): string + { + return InClassNode::class; + } + + /** + * @param InClassNode $node + * @return array)>> + */ + public function processNode(Node $node, Scope $scope): array + { + // return typed properties/all properties + $classLike = $node->getOriginalNode(); + + $propertyCount = count($classLike->getProperties()); + + $missingTypeLines = []; + + foreach ($classLike->getProperties() as $property) { + // blocked by parent type + if ($this->isGuardedByParentClassProperty($scope, $property)) { + continue; + } + + // already typed + if ($property->type instanceof Node) { + continue; + } + + if ($this->isPropertyDocTyped($property)) { + continue; + } + + // give useful context + $missingTypeLines[] = $property->getLine(); + } + + return [$propertyCount, $missingTypeLines]; + } + + private function isPropertyDocTyped(Property $property): bool + { + $docComment = $property->getDocComment(); + if (! $docComment instanceof Doc) { + return false; + } + + $docCommentText = $docComment->getText(); + + // skip as unable to type + return strpos($docCommentText, 'callable') !== false || strpos($docCommentText, 'resource') !== false; + } + + private function isGuardedByParentClassProperty(Scope $scope, Property $property): bool + { + $propertyName = $property->props[0]->name->toString(); + + $classReflection = $scope->getClassReflection(); + if (! $classReflection instanceof ClassReflection) { + return false; + } + + foreach ($classReflection->getParents() as $parentClassReflection) { + if ($parentClassReflection->hasProperty($propertyName)) { + return true; + } + } + + return false; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ReturnTypeDeclarationCollector.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ReturnTypeDeclarationCollector.php new file mode 100644 index 00000000000..f6f63b8419e --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Collectors/ReturnTypeDeclarationCollector.php @@ -0,0 +1,48 @@ +isMagic()) { + return null; + } + + if ($scope->isInTrait()) { + $originalMethodName = $node->getAttribute('originalTraitMethodName'); + if ($originalMethodName === '__construct') { + return null; + } + } + + $missingTypeLines = []; + + if (! $node->returnType instanceof Node) { + $missingTypeLines[] = $node->getLine(); + } + + return [1, $missingTypeLines]; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration.php new file mode 100644 index 00000000000..311d103fadd --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration.php @@ -0,0 +1,77 @@ + + * @readonly + */ + private array $parameters; + + /** + * @param array $parameters + */ + public function __construct(array $parameters) + { + $this->parameters = $parameters; + } + + /** + * @return float|int + */ + public function getRequiredPropertyTypeLevel() + { + return $this->parameters['property'] ?? $this->parameters['property_type']; + } + + public function isConstantTypeCoverageEnabled(): bool + { + // constant types are available only on PHP 8.3+ + if (PHP_VERSION_ID < 80300) { + return false; + } + + return $this->getRequiredConstantTypeLevel() > 0; + } + + /** + * @return float|int + */ + public function getRequiredConstantTypeLevel() + { + return $this->parameters['constant'] ?? $this->parameters['constant_type']; + } + + /** + * @return float|int + */ + public function getRequiredParamTypeLevel() + { + return $this->parameters['param'] ?? $this->parameters['param_type']; + } + + /** + * @return float|int + */ + public function getRequiredReturnTypeLevel() + { + return $this->parameters['return'] ?? $this->parameters['return_type']; + } + + /** + * @return float|int + */ + public function getRequiredDeclareLevel() + { + return $this->parameters['declare']; + } + + public function showOnlyMeasure(): bool + { + return $this->parameters['measure']; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration/ScopeConfigurationResolver.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration/ScopeConfigurationResolver.php new file mode 100644 index 00000000000..4929c86fefa --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Configuration/ScopeConfigurationResolver.php @@ -0,0 +1,60 @@ +getParameter('analysedPaths'); + $analysedPathsFromConfig = $originalContainer->getParameter('analysedPathsFromConfig'); + + self::$areFullPathsAnalysed = $analysedPathsFromConfig === $analysedPaths; + + return self::$areFullPathsAnalysed; + } + + private static function getPrivateProperty(object $object, string $propertyName): object + { + $reflectionProperty = new ReflectionProperty($object, $propertyName); + if (PHP_VERSION_ID < 80100) { + $reflectionProperty->setAccessible(true); + } + + return $reflectionProperty->getValue($object); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Formatter/TypeCoverageFormatter.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Formatter/TypeCoverageFormatter.php new file mode 100644 index 00000000000..04d7c3946aa --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Formatter/TypeCoverageFormatter.php @@ -0,0 +1,56 @@ +getTotalCount() === 0) { + return []; + } + + $typeCoveragePercentage = $typeCountAndMissingTypes->getCoveragePercentage(); + + // has the code met the minimal sea level of types? + if ($typeCoveragePercentage >= $minimalLevel) { + return []; + } + + $ruleErrors = []; + + foreach ($typeCountAndMissingTypes->getMissingTypeLinesByFilePath() as $filePath => $lines) { + $errorMessage = sprintf( + $message, + $typeCountAndMissingTypes->getTotalCount(), + $typeCountAndMissingTypes->getFilledCount(), + $typeCoveragePercentage, + $minimalLevel + ); + + foreach ($lines as $line) { + $ruleErrors[] = RuleErrorBuilder::message($errorMessage) + ->identifier($identifier) + ->file($filePath) + ->line($line) + ->build(); + } + } + + return $ruleErrors; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ConstantTypeCoverageRule.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ConstantTypeCoverageRule.php new file mode 100644 index 00000000000..7fe74a9e0ac --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ConstantTypeCoverageRule.php @@ -0,0 +1,109 @@ + + */ +final class ConstantTypeCoverageRule implements Rule +{ + /** + * @var string + */ + public const ERROR_MESSAGE = 'Out of %d possible constant types, only %d - %.1f %% actually have it. Add more constant types to get over %s %%'; + + /** + * @var string + */ + private const IDENTIFIER = 'typeCoverage.constantTypeCoverage'; + + /** + * @readonly + */ + private TypeCoverageFormatter $typeCoverageFormatter; + + /** + * @readonly + */ + private Configuration $configuration; + + /** + * @readonly + */ + private CollectorDataNormalizer $collectorDataNormalizer; + + public function __construct( + TypeCoverageFormatter $typeCoverageFormatter, + Configuration $configuration, + CollectorDataNormalizer $collectorDataNormalizer + ) { + $this->typeCoverageFormatter = $typeCoverageFormatter; + $this->configuration = $configuration; + $this->collectorDataNormalizer = $collectorDataNormalizer; + } + + /** + * @return class-string + */ + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return RuleError[] + */ + public function processNode(Node $node, Scope $scope): array + { + // enable only on PHP 8.3+ + if (PHP_VERSION_ID < 80300) { + return []; + } + + // if only subpaths are analysed, skip as data will be false positive + if (! ScopeConfigurationResolver::areFullPathsAnalysed($scope)) { + return []; + } + + $constantTypeDeclarationCollector = $node->get(ConstantTypeDeclarationCollector::class); + $typeCountAndMissingTypes = $this->collectorDataNormalizer->normalize($constantTypeDeclarationCollector); + + if ($this->configuration->showOnlyMeasure()) { + $errorMessage = sprintf( + 'Class constant type coverage is %.1f %% out of %d possible', + $typeCountAndMissingTypes->getCoveragePercentage(), + $typeCountAndMissingTypes->getTotalCount() + ); + + return [RuleErrorBuilder::message($errorMessage)->build()]; + } + + if (! $this->configuration->isConstantTypeCoverageEnabled()) { + return []; + } + + return $this->typeCoverageFormatter->formatErrors( + self::ERROR_MESSAGE, + self::IDENTIFIER, + $this->configuration->getRequiredConstantTypeLevel(), + $typeCountAndMissingTypes + ); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/DeclareCoverageRule.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/DeclareCoverageRule.php new file mode 100644 index 00000000000..314c0b59785 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/DeclareCoverageRule.php @@ -0,0 +1,116 @@ + + */ +final class DeclareCoverageRule implements Rule +{ + /** + * @var string + */ + public const ERROR_MESSAGE = 'Out of %d possible declare(strict_types=1), only %d - %.1f %% actually have it. Add more declares to get over %s %%'; + + /** + * @readonly + */ + private Configuration $configuration; + + public function __construct(Configuration $configuration) + { + $this->configuration = $configuration; + } + + /** + * @return class-string + */ + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return RuleError[] + */ + public function processNode(Node $node, Scope $scope): array + { + // if only subpaths are analysed, skip as data will be false positive + if (! ScopeConfigurationResolver::areFullPathsAnalysed($scope)) { + return []; + } + + $requiredDeclareLevel = $this->configuration->getRequiredDeclareLevel(); + + $declareCollector = $node->get(DeclareCollector::class); + $totalPossibleDeclares = count($declareCollector); + + $coveredDeclares = 0; + $notCoveredDeclareFilePaths = []; + + foreach ($declareCollector as $fileName => $data) { + // has declares + if ($data === [true]) { + ++$coveredDeclares; + } else { + $notCoveredDeclareFilePaths[] = $fileName; + } + } + + $declareCoverage = ($coveredDeclares / $totalPossibleDeclares) * 100; + + if ($this->configuration->showOnlyMeasure()) { + $errorMessage = sprintf( + 'Strict declares coverage is %.1f %% out of %d possible', + $declareCoverage, + $totalPossibleDeclares + ); + return [RuleErrorBuilder::message($errorMessage)->build()]; + } + + // not enabled + if ($requiredDeclareLevel === 0) { + return []; + } + + // nothing to handle + if ($totalPossibleDeclares === 0) { + return []; + } + + // we meet the limit, all good + if ($declareCoverage >= $requiredDeclareLevel) { + return []; + } + + $ruleErrors = []; + foreach ($notCoveredDeclareFilePaths as $notCoveredDeclareFilePath) { + $errorMessage = sprintf( + self::ERROR_MESSAGE, + $totalPossibleDeclares, + $coveredDeclares, + $declareCoverage, + $requiredDeclareLevel, + ); + + $ruleErrors[] = RuleErrorBuilder::message($errorMessage)->file($notCoveredDeclareFilePath)->build(); + } + + return $ruleErrors; + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ParamTypeCoverageRule.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ParamTypeCoverageRule.php new file mode 100644 index 00000000000..81df4581fa4 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ParamTypeCoverageRule.php @@ -0,0 +1,108 @@ + + */ +final class ParamTypeCoverageRule implements Rule +{ + /** + * @var string + */ + public const ERROR_MESSAGE = 'Out of %d possible param types, only %d - %.1f %% actually have it. Add more param types to get over %s %%'; + + /** + * @var string + */ + private const IDENTIFIER = 'typeCoverage.paramTypeCoverage'; + + /** + * @readonly + */ + private TypeCoverageFormatter $typeCoverageFormatter; + + /** + * @readonly + */ + private Configuration $configuration; + + /** + * @readonly + */ + private CollectorDataNormalizer $collectorDataNormalizer; + + public function __construct( + TypeCoverageFormatter $typeCoverageFormatter, + Configuration $configuration, + CollectorDataNormalizer $collectorDataNormalizer + ) { + $this->typeCoverageFormatter = $typeCoverageFormatter; + $this->configuration = $configuration; + $this->collectorDataNormalizer = $collectorDataNormalizer; + } + + /** + * @return class-string + */ + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return RuleError[] + */ + public function processNode(Node $node, Scope $scope): array + { + // if only subpaths are analysed, skip as data will be false positive + if (! ScopeConfigurationResolver::areFullPathsAnalysed($scope)) { + return []; + } + + $paramTypeDeclarationCollector = $node->get(ParamTypeDeclarationCollector::class); + + $typeCountAndMissingTypes = $this->collectorDataNormalizer->normalize($paramTypeDeclarationCollector); + + if ($this->configuration->showOnlyMeasure()) { + $errorMessage = sprintf( + 'Param type coverage is %.1f %% out of %d possible', + $typeCountAndMissingTypes->getCoveragePercentage(), + $typeCountAndMissingTypes->getTotalCount() + ); + + $ruleError = RuleErrorBuilder::message($errorMessage) + ->build(); + + return [$ruleError]; + } + + if ($this->configuration->getRequiredParamTypeLevel() === 0) { + return []; + } + + return $this->typeCoverageFormatter->formatErrors( + self::ERROR_MESSAGE, + self::IDENTIFIER, + $this->configuration->getRequiredParamTypeLevel(), + $typeCountAndMissingTypes + ); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/PropertyTypeCoverageRule.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/PropertyTypeCoverageRule.php new file mode 100644 index 00000000000..74edaa06387 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/PropertyTypeCoverageRule.php @@ -0,0 +1,104 @@ + + */ +final class PropertyTypeCoverageRule implements Rule +{ + /** + * @var string + */ + public const ERROR_MESSAGE = 'Out of %d possible property types, only %d - %.1f %% actually have it. Add more property types to get over %s %%'; + + /** + * @var string + */ + private const IDENTIFIER = 'typeCoverage.propertyTypeCoverage'; + + /** + * @readonly + */ + private TypeCoverageFormatter $typeCoverageFormatter; + + /** + * @readonly + */ + private Configuration $configuration; + + /** + * @readonly + */ + private CollectorDataNormalizer $collectorDataNormalizer; + + public function __construct( + TypeCoverageFormatter $typeCoverageFormatter, + Configuration $configuration, + CollectorDataNormalizer $collectorDataNormalizer + ) { + $this->typeCoverageFormatter = $typeCoverageFormatter; + $this->configuration = $configuration; + $this->collectorDataNormalizer = $collectorDataNormalizer; + } + + /** + * @return class-string + */ + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return RuleError[] + */ + public function processNode(Node $node, Scope $scope): array + { + // if only subpaths are analysed, skip as data will be false positive + if (! ScopeConfigurationResolver::areFullPathsAnalysed($scope)) { + return []; + } + + $propertyTypeDeclarationCollector = $node->get(PropertyTypeDeclarationCollector::class); + $typeCountAndMissingTypes = $this->collectorDataNormalizer->normalize($propertyTypeDeclarationCollector); + + if ($this->configuration->showOnlyMeasure()) { + $errorMessage = sprintf( + 'Property type coverage is %.1f %% out of %d possible', + $typeCountAndMissingTypes->getCoveragePercentage(), + $typeCountAndMissingTypes->getTotalCount() + ); + + return [RuleErrorBuilder::message($errorMessage)->build()]; + } + + if ($this->configuration->getRequiredPropertyTypeLevel() === 0) { + return []; + } + + return $this->typeCoverageFormatter->formatErrors( + self::ERROR_MESSAGE, + self::IDENTIFIER, + $this->configuration->getRequiredPropertyTypeLevel(), + $typeCountAndMissingTypes + ); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ReturnTypeCoverageRule.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ReturnTypeCoverageRule.php new file mode 100644 index 00000000000..cee1d65a3d5 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/Rules/ReturnTypeCoverageRule.php @@ -0,0 +1,103 @@ + + */ +final class ReturnTypeCoverageRule implements Rule +{ + /** + * @var string + */ + public const ERROR_MESSAGE = 'Out of %d possible return types, only %d - %.1f %% actually have it. Add more return types to get over %s %%'; + + /** + * @var string + */ + private const IDENTIFIER = 'typeCoverage.returnTypeCoverage'; + + /** + * @readonly + */ + private TypeCoverageFormatter $typeCoverageFormatter; + + /** + * @readonly + */ + private Configuration $configuration; + + /** + * @readonly + */ + private CollectorDataNormalizer $collectorDataNormalizer; + + public function __construct( + TypeCoverageFormatter $typeCoverageFormatter, + Configuration $configuration, + CollectorDataNormalizer $collectorDataNormalizer + ) { + $this->typeCoverageFormatter = $typeCoverageFormatter; + $this->configuration = $configuration; + $this->collectorDataNormalizer = $collectorDataNormalizer; + } + + /** + * @return class-string + */ + public function getNodeType(): string + { + return CollectedDataNode::class; + } + + /** + * @param CollectedDataNode $node + * @return RuleError[] + */ + public function processNode(Node $node, Scope $scope): array + { + // if only subpaths are analysed, skip as data will be false positive + if (! ScopeConfigurationResolver::areFullPathsAnalysed($scope)) { + return []; + } + + $returnSeaLevelDataByFilePath = $node->get(ReturnTypeDeclarationCollector::class); + $typeCountAndMissingTypes = $this->collectorDataNormalizer->normalize($returnSeaLevelDataByFilePath); + + if ($this->configuration->showOnlyMeasure()) { + $errorMessage = sprintf( + 'Return type coverage is %.1f %% out of %d possible', + $typeCountAndMissingTypes->getCoveragePercentage(), + $typeCountAndMissingTypes->getTotalCount() + ); + return [RuleErrorBuilder::message($errorMessage)->build()]; + } + + if ($this->configuration->getRequiredReturnTypeLevel() === 0) { + return []; + } + + return $this->typeCoverageFormatter->formatErrors( + self::ERROR_MESSAGE, + self::IDENTIFIER, + $this->configuration->getRequiredReturnTypeLevel(), + $typeCountAndMissingTypes + ); + } +} diff --git a/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/ValueObject/TypeCountAndMissingTypes.php b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/ValueObject/TypeCountAndMissingTypes.php new file mode 100644 index 00000000000..c539839de58 --- /dev/null +++ b/tools/.phpstan/vendor/tomasvotruba/type-coverage/src/ValueObject/TypeCountAndMissingTypes.php @@ -0,0 +1,75 @@ + + * @readonly + */ + private array $missingTypeLinesByFilePath; + + /** + * @param array $missingTypeLinesByFilePath + */ + public function __construct(int $totalCount, int $missingCount, array $missingTypeLinesByFilePath) + { + $this->totalCount = $totalCount; + $this->missingCount = $missingCount; + $this->missingTypeLinesByFilePath = $missingTypeLinesByFilePath; + } + + public function getTotalCount(): int + { + return $this->totalCount; + } + + public function getFilledCount(): int + { + return $this->totalCount - $this->missingCount; + } + + /** + * @return array + */ + public function getMissingTypeLinesByFilePath(): array + { + return $this->missingTypeLinesByFilePath; + } + + public function getCoveragePercentage(): float + { + if ($this->totalCount === 0) { + return 100.0; + } + + $relative = 100 * ($this->getTypedCount() / $this->totalCount); + + // round down with one decimal, to make error message clear that required value is not reached yet + return floor($relative * 10) / 10; + } + + private function getTypedCount(): int + { + $missingCount = 0; + + foreach ($this->missingTypeLinesByFilePath as $missingTypeLines) { + $missingCount += count($missingTypeLines); + } + + return $this->totalCount - $missingCount; + } +} diff --git a/tools/composer b/tools/composer new file mode 100755 index 00000000000..02740c582be Binary files /dev/null and b/tools/composer differ diff --git a/tools/phive b/tools/phive new file mode 100755 index 00000000000..da56a9d34e0 --- /dev/null +++ b/tools/phive @@ -0,0 +1,1104 @@ +#!/usr/bin/env php + '/vendor/phar-io/executor/src/ExecutorException.php', + 'phario\\executor\\executor' => '/vendor/phar-io/executor/src/Executor.php', + 'phario\\executor\\executorresult' => '/vendor/phar-io/executor/src/ExecutorResult.php', + 'phario\\filesystem\\directory' => '/vendor/phar-io/filesystem/src/Directory.php', + 'phario\\filesystem\\directoryexception' => '/vendor/phar-io/filesystem/src/DirectoryException.php', + 'phario\\filesystem\\exception' => '/vendor/phar-io/filesystem/src/Exception.php', + 'phario\\filesystem\\file' => '/vendor/phar-io/filesystem/src/File.php', + 'phario\\filesystem\\filename' => '/vendor/phar-io/filesystem/src/Filename.php', + 'phario\\filesystem\\filenameexception' => '/vendor/phar-io/filesystem/src/FilenameException.php', + 'phario\\filesystem\\lastmodifieddate' => '/vendor/phar-io/filesystem/src/LastModifiedDate.php', + 'phario\\gnupg\\errorstrings' => '/vendor/phar-io/gnupg/src/ErrorStrings.php', + 'phario\\gnupg\\exception' => '/vendor/phar-io/gnupg/src/Exception.php', + 'phario\\gnupg\\factory' => '/vendor/phar-io/gnupg/src/Factory.php', + 'phario\\gnupg\\gnupg' => '/vendor/phar-io/gnupg/src/GnuPG.php', + 'phario\\manifest\\application' => '/vendor/phar-io/manifest/src/values/Application.php', + 'phario\\manifest\\applicationname' => '/vendor/phar-io/manifest/src/values/ApplicationName.php', + 'phario\\manifest\\author' => '/vendor/phar-io/manifest/src/values/Author.php', + 'phario\\manifest\\authorcollection' => '/vendor/phar-io/manifest/src/values/AuthorCollection.php', + 'phario\\manifest\\authorcollectioniterator' => '/vendor/phar-io/manifest/src/values/AuthorCollectionIterator.php', + 'phario\\manifest\\authorelement' => '/vendor/phar-io/manifest/src/xml/AuthorElement.php', + 'phario\\manifest\\authorelementcollection' => '/vendor/phar-io/manifest/src/xml/AuthorElementCollection.php', + 'phario\\manifest\\bundledcomponent' => '/vendor/phar-io/manifest/src/values/BundledComponent.php', + 'phario\\manifest\\bundledcomponentcollection' => '/vendor/phar-io/manifest/src/values/BundledComponentCollection.php', + 'phario\\manifest\\bundledcomponentcollectioniterator' => '/vendor/phar-io/manifest/src/values/BundledComponentCollectionIterator.php', + 'phario\\manifest\\bundleselement' => '/vendor/phar-io/manifest/src/xml/BundlesElement.php', + 'phario\\manifest\\componentelement' => '/vendor/phar-io/manifest/src/xml/ComponentElement.php', + 'phario\\manifest\\componentelementcollection' => '/vendor/phar-io/manifest/src/xml/ComponentElementCollection.php', + 'phario\\manifest\\containselement' => '/vendor/phar-io/manifest/src/xml/ContainsElement.php', + 'phario\\manifest\\copyrightelement' => '/vendor/phar-io/manifest/src/xml/CopyrightElement.php', + 'phario\\manifest\\copyrightinformation' => '/vendor/phar-io/manifest/src/values/CopyrightInformation.php', + 'phario\\manifest\\elementcollection' => '/vendor/phar-io/manifest/src/xml/ElementCollection.php', + 'phario\\manifest\\elementcollectionexception' => '/vendor/phar-io/manifest/src/exceptions/ElementCollectionException.php', + 'phario\\manifest\\email' => '/vendor/phar-io/manifest/src/values/Email.php', + 'phario\\manifest\\exception' => '/vendor/phar-io/manifest/src/exceptions/Exception.php', + 'phario\\manifest\\extelement' => '/vendor/phar-io/manifest/src/xml/ExtElement.php', + 'phario\\manifest\\extelementcollection' => '/vendor/phar-io/manifest/src/xml/ExtElementCollection.php', + 'phario\\manifest\\extension' => '/vendor/phar-io/manifest/src/values/Extension.php', + 'phario\\manifest\\extensionelement' => '/vendor/phar-io/manifest/src/xml/ExtensionElement.php', + 'phario\\manifest\\invalidapplicationnameexception' => '/vendor/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php', + 'phario\\manifest\\invalidemailexception' => '/vendor/phar-io/manifest/src/exceptions/InvalidEmailException.php', + 'phario\\manifest\\invalidurlexception' => '/vendor/phar-io/manifest/src/exceptions/InvalidUrlException.php', + 'phario\\manifest\\library' => '/vendor/phar-io/manifest/src/values/Library.php', + 'phario\\manifest\\license' => '/vendor/phar-io/manifest/src/values/License.php', + 'phario\\manifest\\licenseelement' => '/vendor/phar-io/manifest/src/xml/LicenseElement.php', + 'phario\\manifest\\manifest' => '/vendor/phar-io/manifest/src/values/Manifest.php', + 'phario\\manifest\\manifestdocument' => '/vendor/phar-io/manifest/src/xml/ManifestDocument.php', + 'phario\\manifest\\manifestdocumentexception' => '/vendor/phar-io/manifest/src/exceptions/ManifestDocumentException.php', + 'phario\\manifest\\manifestdocumentloadingexception' => '/vendor/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.php', + 'phario\\manifest\\manifestdocumentmapper' => '/vendor/phar-io/manifest/src/ManifestDocumentMapper.php', + 'phario\\manifest\\manifestdocumentmapperexception' => '/vendor/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.php', + 'phario\\manifest\\manifestelement' => '/vendor/phar-io/manifest/src/xml/ManifestElement.php', + 'phario\\manifest\\manifestelementexception' => '/vendor/phar-io/manifest/src/exceptions/ManifestElementException.php', + 'phario\\manifest\\manifestloader' => '/vendor/phar-io/manifest/src/ManifestLoader.php', + 'phario\\manifest\\manifestloaderexception' => '/vendor/phar-io/manifest/src/exceptions/ManifestLoaderException.php', + 'phario\\manifest\\manifestserializer' => '/vendor/phar-io/manifest/src/ManifestSerializer.php', + 'phario\\manifest\\noemailaddressexception' => '/vendor/phar-io/manifest/src/exceptions/NoEmailAddressException.php', + 'phario\\manifest\\phpelement' => '/vendor/phar-io/manifest/src/xml/PhpElement.php', + 'phario\\manifest\\phpextensionrequirement' => '/vendor/phar-io/manifest/src/values/PhpExtensionRequirement.php', + 'phario\\manifest\\phpversionrequirement' => '/vendor/phar-io/manifest/src/values/PhpVersionRequirement.php', + 'phario\\manifest\\requirement' => '/vendor/phar-io/manifest/src/values/Requirement.php', + 'phario\\manifest\\requirementcollection' => '/vendor/phar-io/manifest/src/values/RequirementCollection.php', + 'phario\\manifest\\requirementcollectioniterator' => '/vendor/phar-io/manifest/src/values/RequirementCollectionIterator.php', + 'phario\\manifest\\requireselement' => '/vendor/phar-io/manifest/src/xml/RequiresElement.php', + 'phario\\manifest\\type' => '/vendor/phar-io/manifest/src/values/Type.php', + 'phario\\manifest\\url' => '/vendor/phar-io/manifest/src/values/Url.php', + 'phario\\phive\\abstractrequestedpharresolver' => '/src/services/resolver/AbstractRequestedPharResolver.php', + 'phario\\phive\\abstractresolvingstrategy' => '/src/services/resolver/strategy/AbstractResolvingStrategy.php', + 'phario\\phive\\authconfig' => '/src/shared/config/AuthConfig.php', + 'phario\\phive\\authentication' => '/src/shared/http/Authentication.php', + 'phario\\phive\\authexception' => '/src/shared/exceptions/AuthException.php', + 'phario\\phive\\authxmlconfig' => '/src/shared/config/AuthXmlConfig.php', + 'phario\\phive\\authxmlconfigfilelocator' => '/src/shared/config/AuthXmlConfigFileLocator.php', + 'phario\\phive\\basehash' => '/src/shared/hash/BaseHash.php', + 'phario\\phive\\basicauthentication' => '/src/shared/http/authentication/BasicAuthentication.php', + 'phario\\phive\\bearerauthentication' => '/src/shared/http/authentication/BearerAuthentication.php', + 'phario\\phive\\cachebackend' => '/src/shared/http/CacheBackend.php', + 'phario\\phive\\checksumservice' => '/src/services/checksum/ChecksumService.php', + 'phario\\phive\\cli\\coloredconsoleoutput' => '/src/shared/cli/output/ColoredConsoleOutput.php', + 'phario\\phive\\cli\\command' => '/src/shared/cli/Command.php', + 'phario\\phive\\cli\\commandlocator' => '/src/shared/cli/CommandLocator.php', + 'phario\\phive\\cli\\commandlocatorexception' => '/src/shared/cli/CommandLocatorException.php', + 'phario\\phive\\cli\\commandoptionsexception' => '/src/shared/cli/CommandOptionsException.php', + 'phario\\phive\\cli\\consoleinput' => '/src/shared/cli/input/ConsoleInput.php', + 'phario\\phive\\cli\\consoleoutput' => '/src/shared/cli/output/ConsoleOutput.php', + 'phario\\phive\\cli\\consoletable' => '/src/shared/cli/output/ConsoleTable.php', + 'phario\\phive\\cli\\context' => '/src/shared/cli/Context.php', + 'phario\\phive\\cli\\contextexception' => '/src/shared/cli/ContextException.php', + 'phario\\phive\\cli\\generalcontext' => '/src/shared/cli/GeneralContext.php', + 'phario\\phive\\cli\\input' => '/src/shared/cli/input/Input.php', + 'phario\\phive\\cli\\options' => '/src/shared/cli/Options.php', + 'phario\\phive\\cli\\output' => '/src/shared/cli/output/Output.php', + 'phario\\phive\\cli\\outputfactory' => '/src/shared/cli/output/OutputFactory.php', + 'phario\\phive\\cli\\outputlocator' => '/src/shared/cli/output/OutputLocator.php', + 'phario\\phive\\cli\\request' => '/src/shared/cli/Request.php', + 'phario\\phive\\cli\\requestexception' => '/src/shared/cli/RequestException.php', + 'phario\\phive\\cli\\runner' => '/src/shared/cli/Runner.php', + 'phario\\phive\\cli\\runnerexception' => '/src/shared/cli/RunnerException.php', + 'phario\\phive\\commandlocator' => '/src/commands/CommandLocator.php', + 'phario\\phive\\compatibilityservice' => '/src/services/phar/CompatibilityService.php', + 'phario\\phive\\composeralias' => '/src/shared/ComposerAlias.php', + 'phario\\phive\\composercommand' => '/src/commands/composer/ComposerCommand.php', + 'phario\\phive\\composercommandconfig' => '/src/commands/composer/ComposerCommandConfig.php', + 'phario\\phive\\composercontext' => '/src/commands/composer/ComposerContext.php', + 'phario\\phive\\composerservice' => '/src/commands/composer/ComposerService.php', + 'phario\\phive\\compositeauthconfig' => '/src/shared/config/CompositeAuthConfig.php', + 'phario\\phive\\config' => '/src/shared/config/Config.php', + 'phario\\phive\\configexception' => '/src/shared/exceptions/ConfigException.php', + 'phario\\phive\\configuredphar' => '/src/shared/phar/ConfiguredPhar.php', + 'phario\\phive\\configuredpharexception' => '/src/shared/phar/ConfiguredPharException.php', + 'phario\\phive\\curl' => '/src/shared/http/Curl.php', + 'phario\\phive\\curlconfig' => '/src/shared/http/CurlConfig.php', + 'phario\\phive\\curlconfigbuilder' => '/src/shared/http/CurlConfigBuilder.php', + 'phario\\phive\\curlconfigexception' => '/src/shared/exceptions/CurlConfigException.php', + 'phario\\phive\\curlexception' => '/src/shared/exceptions/CurlException.php', + 'phario\\phive\\curlhttpclient' => '/src/shared/http/CurlHttpClient.php', + 'phario\\phive\\defaultcommand' => '/src/commands/default/DefaultCommand.php', + 'phario\\phive\\defaultcommandconfig' => '/src/commands/default/DefaultCommandConfig.php', + 'phario\\phive\\directurlresolver' => '/src/services/resolver/DirectUrlResolver.php', + 'phario\\phive\\downloadfailedexception' => '/src/shared/exceptions/DownloadFailedException.php', + 'phario\\phive\\environment' => '/src/shared/environment/Environment.php', + 'phario\\phive\\environmentauthconfig' => '/src/shared/config/EnvironmentAuthConfig.php', + 'phario\\phive\\environmentexception' => '/src/shared/exceptions/EnvironmentException.php', + 'phario\\phive\\environmentlocator' => '/src/shared/environment/EnvironmentLocator.php', + 'phario\\phive\\errorexception' => '/src/shared/exceptions/ErrorException.php', + 'phario\\phive\\etag' => '/src/shared/http/ETag.php', + 'phario\\phive\\exception' => '/src/shared/exceptions/Exception.php', + 'phario\\phive\\executor' => '/src/shared/executor/Executor.php', + 'phario\\phive\\executorexception' => '/src/shared/exceptions/ExecutorException.php', + 'phario\\phive\\executorresult' => '/src/shared/executor/ExecutorResult.php', + 'phario\\phive\\factory' => '/src/Factory.php', + 'phario\\phive\\featuremissingexception' => '/src/shared/exceptions/FeatureMissingException.php', + 'phario\\phive\\filedownloader' => '/src/shared/download/FileDownloader.php', + 'phario\\phive\\filedownloaderexception' => '/src/shared/FileDownloaderException.php', + 'phario\\phive\\filemigration' => '/src/services/migration/FileMigration.php', + 'phario\\phive\\filenotwritableexception' => '/src/shared/exceptions/FileNotWritableException.php', + 'phario\\phive\\filestoragecachebackend' => '/src/shared/http/FileStorageCacheBackend.php', + 'phario\\phive\\git' => '/src/shared/Git.php', + 'phario\\phive\\gitawarephiveversion' => '/src/shared/version/GitAwarePhiveVersion.php', + 'phario\\phive\\gitexception' => '/src/shared/exceptions/GitException.php', + 'phario\\phive\\githubaliasresolver' => '/src/services/resolver/GithubAliasResolver.php', + 'phario\\phive\\githubaliasresolverexception' => '/src/GithubAliasResolverException.php', + 'phario\\phive\\githubrepository' => '/src/shared/repository/GithubRepository.php', + 'phario\\phive\\gitlabaliasresolver' => '/src/services/resolver/GitlabAliasResolver.php', + 'phario\\phive\\gitlabrepository' => '/src/shared/repository/GitlabRepository.php', + 'phario\\phive\\globalphivexmlconfig' => '/src/shared/config/GlobalPhiveXmlConfig.php', + 'phario\\phive\\gnupg' => '/src/shared/GnuPG.php', + 'phario\\phive\\gnupgkeydownloader' => '/src/services/key/gpg/GnupgKeyDownloader.php', + 'phario\\phive\\gnupgkeydownloaderexception' => '/src/shared/exceptions/GnupgKeyDownloaderException.php', + 'phario\\phive\\gnupgkeyimporter' => '/src/services/key/gpg/GnupgKeyImporter.php', + 'phario\\phive\\gnupgsignatureverifier' => '/src/services/signature/gpg/GnupgSignatureVerifier.php', + 'phario\\phive\\gnupgverificationresult' => '/src/services/signature/gpg/GnupgVerificationResult.php', + 'phario\\phive\\hash' => '/src/shared/hash/Hash.php', + 'phario\\phive\\helpcommand' => '/src/commands/help/HelpCommand.php', + 'phario\\phive\\homepharsxmlmigration' => '/src/services/migration/HomePharsXmlMigration.php', + 'phario\\phive\\homephivexmlmigration' => '/src/services/migration/HomePhiveXmlMigration.php', + 'phario\\phive\\httpclient' => '/src/shared/http/HttpClient.php', + 'phario\\phive\\httpexception' => '/src/shared/http/HttpException.php', + 'phario\\phive\\httpprogresshandler' => '/src/shared/http/HttpProgressHandler.php', + 'phario\\phive\\httpprogressrenderer' => '/src/shared/http/HttpProgressRenderer.php', + 'phario\\phive\\httpprogressupdate' => '/src/shared/http/HttpProgressUpdate.php', + 'phario\\phive\\httpresponse' => '/src/shared/http/HttpResponse.php', + 'phario\\phive\\httpresponseexception' => '/src/shared/http/HttpResponseException.php', + 'phario\\phive\\installationfailedexception' => '/src/shared/exceptions/InstallationFailedException.php', + 'phario\\phive\\installcommand' => '/src/commands/install/InstallCommand.php', + 'phario\\phive\\installcommandconfig' => '/src/commands/install/InstallCommandConfig.php', + 'phario\\phive\\installcommandconfigexception' => '/src/commands/install/InstallCommandConfigException.php', + 'phario\\phive\\installcontext' => '/src/commands/install/InstallContext.php', + 'phario\\phive\\installedphar' => '/src/shared/phar/InstalledPhar.php', + 'phario\\phive\\installservice' => '/src/services/phar/InstallService.php', + 'phario\\phive\\internalfilemigration' => '/src/services/migration/InternalFileMigration.php', + 'phario\\phive\\invalidhashexception' => '/src/shared/exceptions/InvalidHashException.php', + 'phario\\phive\\invalidxmlexception' => '/src/shared/exceptions/InvalidXmlException.php', + 'phario\\phive\\ioexception' => '/src/shared/exceptions/IOException.php', + 'phario\\phive\\jsondata' => '/src/shared/JsonData.php', + 'phario\\phive\\keydownloader' => '/src/services/key/KeyDownloader.php', + 'phario\\phive\\keyimporter' => '/src/services/key/KeyImporter.php', + 'phario\\phive\\keyimportresult' => '/src/services/key/KeyImportResult.php', + 'phario\\phive\\keyservice' => '/src/services/key/KeyService.php', + 'phario\\phive\\linkcreationfailedexception' => '/src/shared/exceptions/LinkCreationFailedException.php', + 'phario\\phive\\listcommand' => '/src/commands/list/ListCommand.php', + 'phario\\phive\\localaliasresolver' => '/src/services/resolver/LocalAliasResolver.php', + 'phario\\phive\\localfirstresolvingstrategy' => '/src/services/resolver/strategy/LocalFirstResolvingStrategy.php', + 'phario\\phive\\localphivexmlconfig' => '/src/shared/config/LocalPhiveXmlConfig.php', + 'phario\\phive\\localrepository' => '/src/shared/repository/LocalRepository.php', + 'phario\\phive\\localsourceslistfileloader' => '/src/shared/sources/LocalSourcesListFileLoader.php', + 'phario\\phive\\localsslcertificate' => '/src/shared/http/LocalSslCertificate.php', + 'phario\\phive\\migratecommand' => '/src/commands/migrate/MigrateCommand.php', + 'phario\\phive\\migratecommandconfig' => '/src/commands/migrate/MigrateCommandConfig.php', + 'phario\\phive\\migratecontext' => '/src/commands/migrate/MigrateContext.php', + 'phario\\phive\\migration' => '/src/services/migration/Migration.php', + 'phario\\phive\\migrationexception' => '/src/shared/exceptions/MigrationException.php', + 'phario\\phive\\migrationfactory' => '/src/services/migration/MigrationFactory.php', + 'phario\\phive\\migrationservice' => '/src/services/migration/MigrationService.php', + 'phario\\phive\\migrationsfailedexception' => '/src/shared/exceptions/MigrationsFailedException.php', + 'phario\\phive\\nogpgbinaryfoundexception' => '/src/shared/exceptions/NoGPGBinaryFoundException.php', + 'phario\\phive\\notfoundexception' => '/src/shared/exceptions/NotFoundException.php', + 'phario\\phive\\outdatedcommand' => '/src/commands/outdated/OutdatedCommand.php', + 'phario\\phive\\outdatedconfig' => '/src/commands/outdated/OutdatedConfig.php', + 'phario\\phive\\outdatedconfigexception' => '/src/commands/outdated/OutdatedConfigException.php', + 'phario\\phive\\outdatedcontext' => '/src/commands/outdated/OutdatedContext.php', + 'phario\\phive\\phar' => '/src/shared/phar/Phar.php', + 'phario\\phive\\pharalias' => '/src/shared/phar/PharAlias.php', + 'phario\\phive\\phardownloader' => '/src/services/phar/PharDownloader.php', + 'phario\\phive\\pharexception' => '/src/shared/exceptions/PharException.php', + 'phario\\phive\\pharidentifier' => '/src/shared/phar/PharIdentifier.php', + 'phario\\phive\\pharinstaller' => '/src/services/phar/PharInstaller.php', + 'phario\\phive\\pharinstallerexception' => '/src/shared/exceptions/PharInstallerException.php', + 'phario\\phive\\pharinstallerfactory' => '/src/services/phar/PharInstallerFactory.php', + 'phario\\phive\\pharinstallerlocator' => '/src/services/phar/PharInstallerLocator.php', + 'phario\\phive\\pharioaliasresolver' => '/src/services/resolver/PharIoAliasResolver.php', + 'phario\\phive\\phariorepository' => '/src/shared/repository/PharIoRepository.php', + 'phario\\phive\\pharregistry' => '/src/shared/PharRegistry.php', + 'phario\\phive\\pharregistryexception' => '/src/shared/exceptions/PharRegistryException.php', + 'phario\\phive\\pharservice' => '/src/services/phar/PharService.php', + 'phario\\phive\\pharurl' => '/src/shared/phar/PharUrl.php', + 'phario\\phive\\phivecontext' => '/src/PhiveContext.php', + 'phario\\phive\\phiveversion' => '/src/shared/version/PhiveVersion.php', + 'phario\\phive\\phivexmlconfig' => '/src/shared/config/PhiveXmlConfig.php', + 'phario\\phive\\phivexmlconfigfilelocator' => '/src/shared/config/PhiveXmlConfigFileLocator.php', + 'phario\\phive\\projectphivexmlmigration' => '/src/services/migration/ProjectPhiveXmlMigration.php', + 'phario\\phive\\publickey' => '/src/services/key/PublicKey.php', + 'phario\\phive\\publickeyexception' => '/src/shared/exceptions/PublicKeyException.php', + 'phario\\phive\\publickeyreader' => '/src/services/key/gpg/PublicKeyReader.php', + 'phario\\phive\\purgecommand' => '/src/commands/purge/PurgeCommand.php', + 'phario\\phive\\purgecontext' => '/src/commands/purge/PurgeContext.php', + 'phario\\phive\\ratelimit' => '/src/shared/http/RateLimit.php', + 'phario\\phive\\release' => '/src/shared/phar/Release.php', + 'phario\\phive\\releasecollection' => '/src/shared/phar/ReleaseCollection.php', + 'phario\\phive\\releaseexception' => '/src/shared/exceptions/ReleaseException.php', + 'phario\\phive\\releaseselector' => '/src/services/phar/ReleaseSelector.php', + 'phario\\phive\\remotefirstresolvingstrategy' => '/src/services/resolver/strategy/RemoteFirstResolvingStrategy.php', + 'phario\\phive\\remotesourceslistfileloader' => '/src/shared/sources/RemoteSourcesListFileLoader.php', + 'phario\\phive\\removalservice' => '/src/services/phar/RemovalService.php', + 'phario\\phive\\removecommand' => '/src/commands/remove/RemoveCommand.php', + 'phario\\phive\\removecommandconfig' => '/src/commands/remove/RemoveCommandConfig.php', + 'phario\\phive\\removecontext' => '/src/commands/remove/RemoveContext.php', + 'phario\\phive\\requestedphar' => '/src/shared/phar/RequestedPhar.php', + 'phario\\phive\\requestedpharresolver' => '/src/services/resolver/RequestedPharResolver.php', + 'phario\\phive\\requestedpharresolverfactory' => '/src/services/resolver/RequestedPharResolverFactory.php', + 'phario\\phive\\requestedpharresolverservice' => '/src/services/resolver/RequestedPharResolverService.php', + 'phario\\phive\\requestedpharresolverservicebuilder' => '/src/services/resolver/RequestedPharResolverServiceBuilder.php', + 'phario\\phive\\resetcommand' => '/src/commands/reset/ResetCommand.php', + 'phario\\phive\\resetcommandconfig' => '/src/commands/reset/ResetCommandConfig.php', + 'phario\\phive\\resetcontext' => '/src/commands/reset/ResetContext.php', + 'phario\\phive\\resolveexception' => '/src/shared/exceptions/ResolveException.php', + 'phario\\phive\\resolvingstrategy' => '/src/services/resolver/strategy/ResolvingStrategy.php', + 'phario\\phive\\retryinghttpclient' => '/src/shared/http/RetryingHttpClient.php', + 'phario\\phive\\ringdowncurlhttpclient' => '/src/shared/http/RingdownCurlHttpClient.php', + 'phario\\phive\\selfupdatecommand' => '/src/commands/selfupdate/SelfupdateCommand.php', + 'phario\\phive\\sha1hash' => '/src/shared/hash/sha/Sha1Hash.php', + 'phario\\phive\\sha256hash' => '/src/shared/hash/sha/Sha256Hash.php', + 'phario\\phive\\sha384hash' => '/src/shared/hash/sha/Sha384Hash.php', + 'phario\\phive\\sha512hash' => '/src/shared/hash/sha/Sha512Hash.php', + 'phario\\phive\\signatureverifier' => '/src/services/signature/SignatureVerifier.php', + 'phario\\phive\\skelcommand' => '/src/commands/skel/SkelCommand.php', + 'phario\\phive\\skelcommandconfig' => '/src/commands/skel/SkelCommandConfig.php', + 'phario\\phive\\skelcontext' => '/src/commands/skel/SkelContext.php', + 'phario\\phive\\source' => '/src/shared/sources/Source.php', + 'phario\\phive\\sourcerepository' => '/src/shared/repository/SourceRepository.php', + 'phario\\phive\\sourceslist' => '/src/shared/sources/SourcesList.php', + 'phario\\phive\\sourceslistexception' => '/src/shared/exceptions/SourcesListException.php', + 'phario\\phive\\sourceslistfileloader' => '/src/shared/sources/SourcesListFileLoader.php', + 'phario\\phive\\staticphiveversion' => '/src/shared/version/StaticPhiveVersion.php', + 'phario\\phive\\statuscommand' => '/src/commands/status/StatusCommand.php', + 'phario\\phive\\statuscommandconfig' => '/src/commands/status/StatusCommandConfig.php', + 'phario\\phive\\statuscontext' => '/src/commands/status/StatusContext.php', + 'phario\\phive\\supportedrelease' => '/src/shared/phar/SupportedRelease.php', + 'phario\\phive\\targetdirectorylocator' => '/src/shared/TargetDirectoryLocator.php', + 'phario\\phive\\tokenauthentication' => '/src/shared/http/authentication/TokenAuthentication.php', + 'phario\\phive\\trustedcollection' => '/src/services/key/TrustedCollection.php', + 'phario\\phive\\unixoidenvironment' => '/src/shared/environment/UnixoidEnvironment.php', + 'phario\\phive\\unixoidpharinstaller' => '/src/services/phar/UnixoidPharInstaller.php', + 'phario\\phive\\unsupportedrelease' => '/src/shared/phar/UnsupportedRelease.php', + 'phario\\phive\\unsupportedversionconstraintexception' => '/src/shared/exceptions/UnsupportedVersionConstraintException.php', + 'phario\\phive\\updatecommand' => '/src/commands/update/UpdateCommand.php', + 'phario\\phive\\updatecommandconfig' => '/src/commands/update/UpdateCommandConfig.php', + 'phario\\phive\\updatecontext' => '/src/commands/update/UpdateContext.php', + 'phario\\phive\\updaterepositorylistcommand' => '/src/commands/update-repository-list/UpdateRepositoryListCommand.php', + 'phario\\phive\\url' => '/src/shared/Url.php', + 'phario\\phive\\urlrepository' => '/src/shared/repository/UrlRepository.php', + 'phario\\phive\\usedphar' => '/src/shared/phar/UsedPhar.php', + 'phario\\phive\\userfilemigration' => '/src/services/migration/UserFileMigration.php', + 'phario\\phive\\verificationfailedexception' => '/src/shared/exceptions/VerificationFailedException.php', + 'phario\\phive\\verificationresult' => '/src/services/signature/VerificationResult.php', + 'phario\\phive\\versioncommand' => '/src/commands/version/VersionCommand.php', + 'phario\\phive\\windowsenvironment' => '/src/shared/environment/WindowsEnvironment.php', + 'phario\\phive\\windowspharinstaller' => '/src/services/phar/WindowsPharInstaller.php', + 'phario\\phive\\xmlfile' => '/src/shared/XmlFile.php', + 'phario\\version\\abstractversionconstraint' => '/vendor/phar-io/version/src/constraints/AbstractVersionConstraint.php', + 'phario\\version\\andversionconstraintgroup' => '/vendor/phar-io/version/src/constraints/AndVersionConstraintGroup.php', + 'phario\\version\\anyversionconstraint' => '/vendor/phar-io/version/src/constraints/AnyVersionConstraint.php', + 'phario\\version\\buildmetadata' => '/vendor/phar-io/version/src/BuildMetaData.php', + 'phario\\version\\exactversionconstraint' => '/vendor/phar-io/version/src/constraints/ExactVersionConstraint.php', + 'phario\\version\\exception' => '/vendor/phar-io/version/src/exceptions/Exception.php', + 'phario\\version\\greaterthanorequaltoversionconstraint' => '/vendor/phar-io/version/src/constraints/GreaterThanOrEqualToVersionConstraint.php', + 'phario\\version\\invalidprereleasesuffixexception' => '/vendor/phar-io/version/src/exceptions/InvalidPreReleaseSuffixException.php', + 'phario\\version\\invalidversionexception' => '/vendor/phar-io/version/src/exceptions/InvalidVersionException.php', + 'phario\\version\\nobuildmetadataexception' => '/vendor/phar-io/version/src/exceptions/NoBuildMetaDataException.php', + 'phario\\version\\noprereleasesuffixexception' => '/vendor/phar-io/version/src/exceptions/NoPreReleaseSuffixException.php', + 'phario\\version\\orversionconstraintgroup' => '/vendor/phar-io/version/src/constraints/OrVersionConstraintGroup.php', + 'phario\\version\\prereleasesuffix' => '/vendor/phar-io/version/src/PreReleaseSuffix.php', + 'phario\\version\\specificmajorandminorversionconstraint' => '/vendor/phar-io/version/src/constraints/SpecificMajorAndMinorVersionConstraint.php', + 'phario\\version\\specificmajorversionconstraint' => '/vendor/phar-io/version/src/constraints/SpecificMajorVersionConstraint.php', + 'phario\\version\\unsupportedversionconstraintexception' => '/vendor/phar-io/version/src/exceptions/UnsupportedVersionConstraintException.php', + 'phario\\version\\version' => '/vendor/phar-io/version/src/Version.php', + 'phario\\version\\versionconstraint' => '/vendor/phar-io/version/src/constraints/VersionConstraint.php', + 'phario\\version\\versionconstraintparser' => '/vendor/phar-io/version/src/VersionConstraintParser.php', + 'phario\\version\\versionconstraintvalue' => '/vendor/phar-io/version/src/VersionConstraintValue.php', + 'phario\\version\\versionnumber' => '/vendor/phar-io/version/src/VersionNumber.php' + ); + } + + $class = strtolower($class); + + if (isset($classes[$class])) { + require 'phar://phive.phar/' . $classes[$class]; + } + } +); + +Phar::mapPhar('phive.phar'); + +$rc = (new Factory(new Cli\Request($_SERVER['argv']), new StaticPhiveVersion('0.16.0')))->getRunner()->run(); +exit($rc); + +__HALT_COMPILER(); ?> +nX= +phive.phar+vendor/phar-io/filesystem/src/Directory.php�9?�g���4vendor/phar-io/filesystem/src/DirectoryException.php�9?�g�=v�"�+vendor/phar-io/filesystem/src/Exception.phpf9?�g^�$��&vendor/phar-io/filesystem/src/File.phpf9?�g�C�+r�*vendor/phar-io/filesystem/src/Filename.php� 9?�g�Vs�)�3vendor/phar-io/filesystem/src/FilenameException.phpm9?�gbfo���2vendor/phar-io/filesystem/src/LastModifiedDate.php�9?�gT���[�(vendor/phar-io/executor/src/Executor.php9?�g�#�j~�1vendor/phar-io/executor/src/ExecutorException.php�9?�gg�13�,vendor/phar-io/version/src/VersionNumber.php�9?�gkJ}�r�6vendor/phar-io/manifest/src/ManifestDocumentMapper.php�9?�g��q���.vendor/phar-io/manifest/src/ManifestLoader.php�9?�g�q�̤2vendor/phar-io/manifest/src/ManifestSerializer.php�9?�gM�ۂ��Evendor/phar-io/manifest/src/exceptions/ElementCollectionException.php9?�g0_Uj�4vendor/phar-io/manifest/src/exceptions/Exception.php�9?�g��P��Jvendor/phar-io/manifest/src/exceptions/InvalidApplicationNameException.php19?�gFM�V��@vendor/phar-io/manifest/src/exceptions/InvalidEmailException.php9?�g+�ˤ>vendor/phar-io/manifest/src/exceptions/InvalidUrlException.php9?�g/�Y��Dvendor/phar-io/manifest/src/exceptions/ManifestDocumentException.php�9?�g'�� o�Kvendor/phar-io/manifest/src/exceptions/ManifestDocumentLoadingException.php�9?�g!��գ�Jvendor/phar-io/manifest/src/exceptions/ManifestDocumentMapperException.php�9?�g0`'�i�Cvendor/phar-io/manifest/src/exceptions/ManifestElementException.php�9?�g%#mߤBvendor/phar-io/manifest/src/exceptions/ManifestLoaderException.php�9?�g�4o��Bvendor/phar-io/manifest/src/exceptions/NoEmailAddressException.php9?�g4�q:�2vendor/phar-io/manifest/src/values/Application.php�9?�g5f��=�6vendor/phar-io/manifest/src/values/ApplicationName.php�9?�g��-vendor/phar-io/manifest/src/values/Author.php9?�g�vendor/phar-io/manifest/src/values/PhpExtensionRequirement.php�9?�gw�(��<vendor/phar-io/manifest/src/values/PhpVersionRequirement.php$9?�g��"�&�2vendor/phar-io/manifest/src/values/Requirement.php�9?�g 1�q��<vendor/phar-io/manifest/src/values/RequirementCollection.php\9?�g�X?��Dvendor/phar-io/manifest/src/values/RequirementCollectionIterator.php�9?�g�� �+vendor/phar-io/manifest/src/values/Type.php�9?�g�<�2�*vendor/phar-io/manifest/src/values/Url.php�9?�g�#lͣ�1vendor/phar-io/manifest/src/xml/AuthorElement.php�9?�gn���2�;vendor/phar-io/manifest/src/xml/AuthorElementCollection.phpS9?�gS(�7�2vendor/phar-io/manifest/src/xml/BundlesElement.phpz9?�gf��}�4vendor/phar-io/manifest/src/xml/ComponentElement.php�9?�g`$Sg�>vendor/phar-io/manifest/src/xml/ComponentElementCollection.php\9?�gT6� �3vendor/phar-io/manifest/src/xml/ContainsElement.php�9?�g�a��Τ4vendor/phar-io/manifest/src/xml/CopyrightElement.php 9?�g}�t)T�5vendor/phar-io/manifest/src/xml/ElementCollection.php�9?�g�砲L�.vendor/phar-io/manifest/src/xml/ExtElement.php9?�gK����8vendor/phar-io/manifest/src/xml/ExtElementCollection.phpJ9?�gQ���4vendor/phar-io/manifest/src/xml/ExtensionElement.php�9?�ga�z�j�2vendor/phar-io/manifest/src/xml/LicenseElement.php|9?�g\t�TX�4vendor/phar-io/manifest/src/xml/ManifestDocument.php 9?�g9�S�3vendor/phar-io/manifest/src/xml/ManifestElement.phpn9?�g��p��.vendor/phar-io/manifest/src/xml/PhpElement.php9?�g��wO�3vendor/phar-io/manifest/src/xml/RequiresElement.phpK9?�g^��ܗ�)src/commands/composer/ComposerContext.php�9?�g�x���)src/commands/composer/ComposerCommand.php�9?�g��`^��/src/commands/composer/ComposerCommandConfig.php9?�g�l� Ť)src/commands/composer/ComposerService.php 9?�g,�����'src/commands/default/DefaultCommand.php,9?�g���e�-src/commands/default/DefaultCommandConfig.php�9?�gt@�k��src/commands/help/help.md� +9?�g�$4w�!src/commands/help/HelpCommand.php�9?�g�J�D��6src/commands/install/InstallCommandConfigException.php�9?�g2��=�'src/commands/install/InstallContext.phpN9?�g�|S���-src/commands/install/InstallCommandConfig.php{9?�g��k�'src/commands/install/InstallCommand.php� +9?�g��;��!src/commands/list/ListCommand.php�9?�gD|��'src/commands/migrate/MigrateContext.php9?�gPX'�e�'src/commands/migrate/MigrateCommand.php�9?�g�� �"�-src/commands/migrate/MigrateCommandConfig.phpt9?�gt��W¤1src/commands/outdated/OutdatedConfigException.php�9?�g�-4��)src/commands/outdated/OutdatedContext.php49?�g�#>��(src/commands/outdated/OutdatedConfig.php99?�g� �� �)src/commands/outdated/OutdatedCommand.phpQ9?�gPK��5�#src/commands/purge/PurgeContext.php�9?�gf��P�#src/commands/purge/PurgeCommand.phps9?�g�(Ҥ%src/commands/remove/RemoveContext.php9?�gQ'���%src/commands/remove/RemoveCommand.php 9?�g0��M�+src/commands/remove/RemoveCommandConfig.php9?�g���/@�#src/commands/reset/ResetContext.php�9?�g�E�Ŵ#src/commands/reset/ResetCommand.php09?�gr#�\��)src/commands/reset/ResetCommandConfig.php9?�g�I��Ť-src/commands/selfupdate/SelfupdateCommand.php�9?�g�gY�U�!src/commands/skel/SkelContext.php29?�gX�_Mʹ'src/commands/skel/SkelCommandConfig.php9?�g�!�E�!src/commands/skel/SkelCommand.phph 9?�g�V����%src/commands/status/StatusContext.php�9?�gt�&��%src/commands/status/StatusCommand.php� 9?�g�����+src/commands/status/StatusCommandConfig.phpI +9?�g<U氝�Csrc/commands/update-repository-list/UpdateRepositoryListCommand.php�9?�g�8H�j�%src/commands/update/UpdateContext.php�9?�gz�f�%src/commands/update/UpdateCommand.php9?�g���k��+src/commands/update/UpdateCommandConfig.php 9?�g�@�$��'src/commands/version/VersionCommand.php 9?�gO���src/commands/CommandLocator.phpq +9?�g��X@�)src/services/checksum/ChecksumService.php89?�g 2w��+src/services/key/gpg/GnupgKeyDownloader.phpt +9?�g��ݴ)src/services/key/gpg/GnupgKeyImporter.php�9?�g���~�(src/services/key/gpg/PublicKeyReader.php�9?�g5��W�"src/services/key/KeyDownloader.php�9?�g�}.e� src/services/key/KeyImporter.php�9?�g�j�$src/services/key/KeyImportResult.phpa9?�g��AG��src/services/key/KeyService.php 9?�g���U�src/services/key/PublicKey.php�9?�gr:F?�&src/services/key/TrustedCollection.php�9?�g��a~ �(src/services/migration/FileMigration.php�9?�g�t ;Y�0src/services/migration/HomePhiveXmlMigration.php>9?�g�?겴0src/services/migration/InternalFileMigration.phpY9?�gm���@�$src/services/migration/Migration.php�9?�g�X'mY�3src/services/migration/ProjectPhiveXmlMigration.php�9?�g;9̴,src/services/migration/UserFileMigration.php�9?�g`�p�0src/services/migration/HomePharsXmlMigration.phpl9?�g�]]&�+src/services/migration/MigrationFactory.php�9?�g�r�A�+src/services/migration/MigrationService.php�9?�g��H4�$src/services/phar/PharDownloader.phpV9?�gx�^��#src/services/phar/PharInstaller.php� 9?�g 5�JԴ*src/services/phar/PharInstallerFactory.php�9?�g��� �*src/services/phar/PharInstallerLocator.php-9?�g��V��!src/services/phar/PharService.php�9?�g�s���%src/services/phar/ReleaseSelector.php� 9?�gm��*src/services/phar/UnixoidPharInstaller.php79?�g�n0ޱ�*src/services/phar/WindowsPharInstaller.php�9?�g��G��$src/services/phar/InstallService.phpv 9?�g����*src/services/phar/CompatibilityService.php� 9?�g�>�~^�$src/services/phar/RemovalService.phpu9?�g��%�<src/services/resolver/strategy/AbstractResolvingStrategy.php 9?�g+ז� �>src/services/resolver/strategy/LocalFirstResolvingStrategy.php]9?�gqM;B�?src/services/resolver/strategy/RemoteFirstResolvingStrategy.php^9?�gr��ٴ4src/services/resolver/strategy/ResolvingStrategy.php�9?�g-W$���7src/services/resolver/AbstractRequestedPharResolver.php09?�g82�Q�+src/services/resolver/DirectUrlResolver.php�9?�g7�k��-src/services/resolver/GitlabAliasResolver.phpG9?�g��v㵴,src/services/resolver/LocalAliasResolver.php9?�g��_���-src/services/resolver/PharIoAliasResolver.php� 9?�gI�D�X�/src/services/resolver/RequestedPharResolver.php49?�gW�R/�6src/services/resolver/RequestedPharResolverFactory.php49?�g.�?L�6src/services/resolver/RequestedPharResolverService.phpW9?�g�z��N�=src/services/resolver/RequestedPharResolverServiceBuilder.php�9?�g�+��&�-src/services/resolver/GithubAliasResolver.phpt 9?�g@�Zt�6src/services/signature/gpg/GnupgVerificationResult.php�9?�gkL�5src/services/signature/gpg/GnupgSignatureVerifier.php89?�g�e '8�,src/services/signature/SignatureVerifier.php�9?�g>P���-src/services/signature/VerificationResult.php49?�gJO���src/shared/cli/input/Input.php�9?�g()D�U�%src/shared/cli/input/ConsoleInput.php�9?�g�K�﨤'src/shared/cli/output/ConsoleOutput.php� +9?�gy�T:|�&src/shared/cli/output/ConsoleTable.php�9?�gr�d#;� src/shared/cli/output/Output.php�9?�g^���J�'src/shared/cli/output/OutputFactory.php�9?�g[Q�@�.src/shared/cli/output/ColoredConsoleOutput.php[9?�g;�b�'src/shared/cli/output/OutputLocator.phpg9?�g� A��src/shared/cli/Command.php�9?�gǯG�*src/shared/cli/CommandLocatorException.php�9?�g&�t��*src/shared/cli/CommandOptionsException.php�9?�g<��@�src/shared/cli/Context.phpz9?�g��4nN�#src/shared/cli/ContextException.php�9?�g/�U�#src/shared/cli/RequestException.php9?�gGM�ꪴ"src/shared/cli/RunnerException.php�9?�gm;g��src/shared/cli/error.txtR9?�g���'�!src/shared/cli/CommandLocator.php�9?�g7��o6�!src/shared/cli/GeneralContext.phpB 9?�g����src/shared/cli/Options.php�9?�g����6�src/shared/cli/Request.php9?�gu�7N�src/shared/cli/Runner.phpV9?�gE0��N� src/shared/config/AuthConfig.php�9?�g,d���#src/shared/config/AuthXmlConfig.php 9?�g�S�঴.src/shared/config/AuthXmlConfigFileLocator.phpx9?�gf6�ô)src/shared/config/CompositeAuthConfig.php�9?�g�1z���*src/shared/config/GlobalPhiveXmlConfig.php@9?�g_�fK[�)src/shared/config/LocalPhiveXmlConfig.php�9?�g��q�ٴ/src/shared/config/PhiveXmlConfigFileLocator.php)9?�gWQwŴ+src/shared/config/EnvironmentAuthConfig.php�9?�g�Vo��$src/shared/config/PhiveXmlConfig.php�#9?�gh} M�src/shared/config/Config.php�9?�g���5�&src/shared/download/FileDownloader.phpj 9?�gFcz���-src/shared/environment/EnvironmentLocator.php�9?�g�����-src/shared/environment/WindowsEnvironment.php�9?�g��� |�-src/shared/environment/UnixoidEnvironment.php +9?�g�Rs���&src/shared/environment/Environment.php=9?�g'f)��'src/shared/exceptions/AuthException.php�9?�g Z +P��)src/shared/exceptions/ConfigException.php�9?�g �.�´-src/shared/exceptions/CurlConfigException.php�9?�g�?c��'src/shared/exceptions/CurlException.php�9?�g α���1src/shared/exceptions/DownloadFailedException.php�9?�g˫)$�.src/shared/exceptions/EnvironmentException.php�9?�g��bb�(src/shared/exceptions/ErrorException.php�9?�g I��W�#src/shared/exceptions/Exception.php�9?�g +�<���+src/shared/exceptions/ExecutorException.php�9?�g.��1src/shared/exceptions/FeatureMissingException.php�9?�g����2src/shared/exceptions/FileNotWritableException.php�9?�g�g )�&src/shared/exceptions/GitException.php�9?�g +�=��5src/shared/exceptions/GnupgKeyDownloaderException.php�9?�g��m8�%src/shared/exceptions/IOException.php�9?�g +�˸˴5src/shared/exceptions/InstallationFailedException.php�9?�gu�.src/shared/exceptions/InvalidHashException.php�9?�g`o��-src/shared/exceptions/InvalidXmlException.php�9?�g��}�5src/shared/exceptions/LinkCreationFailedException.php�9?�gH@!g�,src/shared/exceptions/MigrationException.php�9?�g �g�3src/shared/exceptions/MigrationsFailedException.php�9?�gtshg�3src/shared/exceptions/NoGPGBinaryFoundException.php�9?�g� G?�+src/shared/exceptions/NotFoundException.php�9?�g�A�)�'src/shared/exceptions/PharException.php�9?�g +2eh״0src/shared/exceptions/PharInstallerException.php�9?�g�B��/src/shared/exceptions/PharRegistryException.php�9?�g�Qz-�,src/shared/exceptions/PublicKeyException.php�9?�g���L�*src/shared/exceptions/ReleaseException.php�9?�g |���*src/shared/exceptions/ResolveException.php�9?�g �Db�.src/shared/exceptions/SourcesListException.php�9?�g)z�/�?src/shared/exceptions/UnsupportedVersionConstraintException.php�9?�g��R�5src/shared/exceptions/VerificationFailedException.php�9?�gV��&� src/shared/executor/Executor.php9?�gZ'&�/�&src/shared/executor/ExecutorResult.php"9?�g��8�� src/shared/hash/sha/Sha1Hash.phpL9?�g���|��"src/shared/hash/sha/Sha256Hash.phpR9?�g�$�U�"src/shared/hash/sha/Sha384Hash.phpR9?�g�-G���"src/shared/hash/sha/Sha512Hash.phpS9?�g��Cc��src/shared/hash/BaseHash.phpN9?�g���qQ�src/shared/hash/Hash.php9?�gB.�� �6src/shared/http/authentication/BasicAuthentication.php�9?�g��B-��7src/shared/http/authentication/BearerAuthentication.php�9?�g/��'I�6src/shared/http/authentication/TokenAuthentication.php�9?�g/E�� src/shared/http/CacheBackend.phpL9?�gS�4�src/shared/http/Curl.phpu +9?�glBi��!src/shared/http/HttpException.php�9?�gfd�_�'src/shared/http/HttpProgressHandler.php�9?�g� Y�_�)src/shared/http/HttpResponseException.php�9?�gmȑA�"src/shared/http/Authentication.php�9?�g�����src/shared/http/CurlConfig.phpG9?�g��� �%src/shared/http/CurlConfigBuilder.php9?�g �����src/shared/http/ETag.php29?�gPxp�r�+src/shared/http/FileStorageCacheBackend.php�9?�g�9[i�(src/shared/http/HttpProgressRenderer.php� +9?�g��F��&src/shared/http/HttpProgressUpdate.php�9?�g'mKdĤ'src/shared/http/LocalSslCertificate.php�9?�g��ۥ��src/shared/http/RateLimit.php(9?�g���$�src/shared/http/HttpClient.php�9?�g1K �e� src/shared/http/HttpResponse.php�9?�g|���&src/shared/http/RetryingHttpClient.php�9?�gp+��@�*src/shared/http/RingdownCurlHttpClient.phpn 9?�g� ��T�"src/shared/http/CurlHttpClient.php�9?�gC�DU�+src/shared/phar/ConfiguredPharException.php�9?�g/4@ý�"src/shared/phar/PharIdentifier.php�9?�gl��I�src/shared/phar/Release.php9?�g8�E�ȴ%src/shared/phar/ReleaseCollection.phpH9?�g�cG�!src/shared/phar/InstalledPhar.php?9?�g)7�src/shared/phar/PharAlias.phpv9?�gm��y��&src/shared/phar/UnsupportedRelease.php9?�g��-� �"src/shared/phar/ConfiguredPhar.php3 9?�g�o��src/shared/phar/Phar.php�9?�g��=@j�!src/shared/phar/RequestedPhar.php� +9?�g�0�$src/shared/phar/SupportedRelease.php�9?�gO��1�src/shared/phar/UsedPhar.phpv9?�g�<����src/shared/phar/PharUrl.php�9?�gb�,g�*src/shared/repository/SourceRepository.php�9?�g*�d�д*src/shared/repository/GitlabRepository.phpI +9?�g� 2t��)src/shared/repository/LocalRepository.php�9?�g� im��*src/shared/repository/PharIoRepository.php( +9?�g{���'src/shared/repository/UrlRepository.php9?�gV$t�*src/shared/repository/GithubRepository.php� +9?�g����ۤ,src/shared/sources/SourcesListFileLoader.php�9?�g9�>K�1src/shared/sources/LocalSourcesListFileLoader.phpC9?�g�n�CҤ2src/shared/sources/RemoteSourcesListFileLoader.php9?�g�sSD�src/shared/sources/Source.php\9?�g �[ �"src/shared/sources/SourcesList.php� 9?�g!dN��+src/shared/version/GitAwarePhiveVersion.php�9?�g%��BǴ#src/shared/version/PhiveVersion.php�9?�g��L++�)src/shared/version/StaticPhiveVersion.phpa9?�g`V�kشsrc/shared/ComposerAlias.php^9?�gI�����&src/shared/FileDownloaderException.php�9?�g���f�src/shared/Git.phpV9?�g�5<�Ӵsrc/shared/JsonData.phpM9?�g�讛 �%src/shared/TargetDirectoryLocator.php�9?�gyH>Of�src/shared/PharRegistry.php~&9?�gc�� �src/shared/XmlFile.phpm 9?�g8�j��src/shared/GnuPG.phpX9?�g0���src/shared/Url.php/ 9?�g ���Ф$src/GithubAliasResolverException.php�9?�g��Q��src/PhiveContext.php�9?�g�4��k�src/autoload.php�S9?�g1 "w|��src/Factory.php�F9?�g� +�(��conf/auth.skeleton.xmld9?�gR�&�ٴ conf/auth.xsd�9?�g���:%�conf/pharBat.template%9?�g'����conf/phive.skeleton.xml�9?�gR��conf/pgp-keyservers.phpG9?�gAfd��Wmo�F ��_�v�$e��t�:s�"M�����)��DY�Hw��$h�߇;�X�d7��O�D>$RO��� B ��դx@s��P� ��`)�1S���O�ý&L�{� aZ�[�0 ���K����S`�|{;S|���1�� �,_$<�(q)`>�Ф���ۚ{��ڛ_�b��'(t��\�����x��܅Y�r�[ �-݂�zr��K^�"���rε�x0�w`Z�oUP��lx�l��l��I�f �u����1���@��I6ɨ��.Kd���M S(L.��6��"��1��13�'�Q�W��M�EW�@H1L���� S�k `6�Q?ȟ�!KX�R!���zBZ�L)v?�1�ȭ�j�i�W�Dcw�%�<]��”qQ��{dYh9�׆3d.��aI�q��V��;�î�˴X)�B�Y�!�L.�;魓�X�'��m�[fW1�4��$`x�N6���9ca 5h�39^7�B!�i?z�u�j�?�?� �����ys����?��+���o�Va��k}H�7�5�(��­�ͣ壖{"y�ˍ ���k�������o +A�l���نW��Z!���M�z���w��b%�c�QqqV������,��u8��?N4�� ҷ���m�= �0���~ō:����:�����Air�4��] +���/��u�Z&o2OD�#�hI,X�lZA0=K2�x�Ln�q��E�� +�����Ls� �I] ȃr����@DL��w��(��n���hy�U�b��(7�y�X����h?b�G�7���Ͳx� Eȱ +�@ �=O�����8��Mp$�<8�pɠ�������z[�h���GMs�玟MKE6����U�w�>)c<=��D�ŝ߇�"�q��<���?]�PMk�0 ��W�ЃZʮ��m +� z�SC�K ���>��iɺMG��}=>���'�Z���.���*N��6o���}kkܟ�� ajMqg!�Yϝ�2>C��>�N3��0��C�v��i���ۏ�8�ΰm�iqh �Qq��'�Ģ���ęqei�IXX�Z��������徫9��ju��*����$%�� �Iy*� +�r1�$9�M����I�D~�FJ���4"W���MJ��/��[o�J���S��6"����4iKu"�i�pt�6���޵v�!��w��|�6 /�z�7;���߽O�����ܧ �4�����H�M�|����[��� |���r4�3쒵�_��l2��g����&�l9������^�I�$�a*}�J�f�+iH�>����܃_����)���*�(i���n&3����*�FJ��3Y�� KzRJsB.pS՘� ��/\��r�����5'�$��Cp���J��Z���Ů�tZ�Ss]#��8@���*A��P;f[�&�£�� ��O�}�A�����_?�Y�[�O\�OJ�]�����i_����%��&�����4��Bm����M)��?EZ�@����x���u��L��Y?� Exs��z�v�U˴� :P 4_*{�d�:�L��Κ��c�S�z��ڮTu���ζxg�ʧY�-��9/�T5�X�I��5v�ڴ�#�r�X�E>.ۣd,����J��~gmnW�+�*��Ҹ{�4v؏I4��ΙWp�pxs83δ���c�p��5k�^���Eg�M�|���;��n��⩦�Q-���Ns{��98�r���6���<��dak+|� +��&ԫ�I��#\�o�8�z`0��N��� 3�U<���a��''�Ji�B(��� F����?;�txʕ[8��u�p�̱��z�u���;r} 7�C��U�X���|j[� �8�^_b��o���T���}�_�)�߬�����m���ayw�uY��=���/�(PHIM�I,J�(.)�L.�/�,H-V�U0Դ��K�M-.HLNU�H,�̏q��I �,.I͵��J�I,.V �ԹV$��d��)�V���+ D��j�u�MK�@���#��xM�z�BAQ�� +e��������"��ij���eٝ��}f��*+�I(t�xvR�y��m:� j� +����.�R���3�q ��� z~��,$�O�?�h8lN��,Bn.5ʹ�W����9+'��� o�����^))���`i ,��Ϯ��%���#ĀK�o�)�t]B�.�!s���C�7 ��[PN��p������:�{F]%�0 �pM�KkH;���L8B���zj�FN����ݙ���3��$W�&D�(��{M�Y��9(� �e� w ��pĵ3��'U$GۓI�oU�7����h.n5�`e���f���� w�/�SAn�0��[CF$Æ�v�����h�����" ��LR�{AEbHYM�C̋���hgt�UW:��AҌ#����S���ȝUf�e�B�V����,6��g���׌z����Y��|�̰z�\5 ���0��5B!g�x/d� ����Br������ݮNr+�l�X�W�< +;����ؠ$g�C�ς,Cv���(d��(� 8��FH{(B۟�)����I�3�Ta]3s<��0zh7Y�e�L7 �x1E$i�rV;;���Xw�ħ�������ݛ �:e���uD��ʨ'J�ڇ ���b����cw��(�D��_�e���m�Ӓ.ȟQ׃���#�)nc2��� + ���N�cd�q ΰ�9=�]�~({���'�(4� �Y7JPD��]�7�/�c���߰��U�1 +�P �=���`�gq��"�K�*��Ѥ�xwq���|�K%�FeQ<�n>MeO� +������|�A[�́�G�[$�W�mF�S����Ӫ���7}��?O�0�w�JT({ U�@0�\�4��:���*�叓6 �%���ݽ���M,�<��r!�5��l>�G)<\2&R���7�|Jpb `E� <8�#Tz__-�Ӣ:p�p%L�q�[;9"�6O��>�i�%��Vf'���(�hG���% �r�Y=@3����Wh��4�mO��m�|{-H �M��,�U>0oK]é�VԧD�����Y�IU�P�p;�P���I�����Q�֘tt2�޽ҹ�y׵��c��B���!�%���`N�ž��/e�#��ЧpS�U����'�Y�~�\m��6��>��,��nbImKN.w�������$9���@˴�m�TH���E���(�b��{n>I����b��<��ݱ#;V7T���(^��5��i�=�^}�BЖ�֌��z+��G����݋uC�&o��jcM���!�|� yO;r`�)j؎2.�?����̣T�1c��ɞ����t�oX�7� �)o��-���P{�F�0,�`���TcX1o��t۰�˳��pI����򜦓�H����\k���{����dG ���f����j1�1D�]'&p�ف��X˝��լڼe��E��aJ$ܡ������˃�+�*��`�®�wJ>��0�)�>J��� h�:�C:�'ip�Z�&�f�@.o����C���+3���G���D0:*-濌�������� =R�k�N���C��(ڴ'pfi�@�µӝ�d�'CL�z!�Q:Ư-"ԛr�(��/�c5\r�uO�����/��Q>9�#>\���ҤUE�o�ž&'�z����KR9)���F�%������`���~�U�!���u 8_/��U�e��믃����׳�#,W�8�ю��[t��#��3��=�{��k�ʛO�}�|����]� ���� 6��x�Yg{�j���8�W*j��w/[,<�o��<�"K��=u\�� ��${�,��b�[�*x��h{�X&&�4�6!t�,�R}wXN����C/{�n��\4�b�0[��ϊif�b��!y��Z����e�?���0�=�,+f����f�- ��X��]yJ-Wm���cQ���U-��W�q� �O���>"L���{B�*@�@6[ϋlZ��eaGY���O<��x�yvF�d-̽{t��Cqfy +� n8m����*���r�0xCDN8/1So����b��h�m#��b3Q?�)�����I��*{��3�M� �µ�:��W��x�R����@��ydM�;�kR��C�P��Cױ� +�[O"��es�Er��0� �&A���y�$ ��;�$2%� �d��ҐI@���g�L�l�¨t�h����M��\O���}�4�tȺ^GhxN̐=\c������J���E� �<�f��D�� z�Ұ��/�� 1��`��f��H�r{�@M�`|��ʑ*Z�g���F��K3p|i�$��fJBȹ�O���1�nȎ뮡'r��\>�:b ���.��<[��p /d���\� T�ݱ����2"]4�q�G [Ƽx�̿�6_���V4 ��̦��F�H��X�.����+�I=eFr�f��\�F�H�����y�P���2���D�;v��)�<��i�+җ���>*H��.����`%�j��#tgs/��Xj�]`�g��T�<���%J��.��|d֚�$J�L�=��H��t�Ƚ�{.�KM2�������פ�=aȣ�yT�C�IT?PPb�0e���f���=�B��/Q7��/������C6a��ۘd��C�E":�]�w��1#/��ۘ� 1]��W_�&���e}���#!;3pt��� ?3��KϏGNȑ�s���^�C�Y���G����~��չ�;)����>�Ϗ��E�m@>��똩��.�ZzG���<� Ֆ�v(�]��;��$_ΉC:�5�*�#7GBmz��kz��2��!����% >+� �?�F�/���Z�ۻ��Y�e�+�kց��4 S����L��Fi�(U�Q���Cl�8 ~�C��s�’�KK�N�pZ�"���#ƾKŖ�������� [����~o BU1j�5I�n�X�3�l9<=뜲��q'w �<*%�3�n��>����6�,;g%�3�1��av�n�mS���r�����2�&[��u��OUp��� �[��֫���\W>ﮪo� +�E�u��.ܻ��!�"k�b�M���R�G.v�q�&[�4�_���\��]T�y3����8�@��>�T��t�j�ЈFh�F�k�.��@[v 7�������qQ�JX�-\��q!���4�Yh)��{3��;tI +�]�'�3�� +l}V'B� �P�3�dH�� �r'��ܵ�[��|�C�@��+�?��V>MEƸ'�pQFF-�.L����l�MM��Q��3Λ����m ;f� �pe޼���m& ��Q9���*��z� v;7�F�h�$��χ��:���e�B?2�B�=�U�]@��"�$�_�?�B��H�]D�aC����������.�������P��*�լ�7qO�b��V�����w;�����Ag�0���?���Z��KX�34�.r�|f�y��l�|���z���Wl����D9{�����9����W�H�!��CV�˦W"�q��(�$ c�ү_̵��ɮ��e��[�=� ��[�J��xB?���z#���({6��<���7𩦈r�Gƣ�RUɞ7�A(Waui�]Ȩǝ�s��{�:�s�픐N��ӈ����B�[�8[�K�\�i�Y h��|O��W��:��Q�h̶�W.ѝ�:d�̣.�#)]�o��"|�����:�AbY^�`�e�d�T���Kt:�� ��6^2�*�^�N��y�w�L�j���LL"oU�U�!����ZHd��h>�[�jv�� +젱S|�^��se�u��,m���Ξ2?�����;��� +�S�U�ʏ����D�9�ڱ=�5�_ՠ�����uJv��� �P艶_�g�9x�S-=9 v!Ɛ�<�� ++�c�O\-)f�\K�@�m8Չv�j;z�/�y��a� % �{��W�1��L��֓*[V��d��T���?���fWYZ����F���z(6��F�9������������@8�*C�v�rM��F���"�K_�*���y� �J�1���\���s�A�V�����?0�7RHƟF ��M�RHT�M#���)��S�����nQ���\�X���Y��S��dͣ��1�m�T��*�//��=�f��o �Fn7�h �[��+W�f]��a�qӾ�Q�q�%��O�n�^����J8㽙� l�BxڤY +�j�~���/ݶIw�{��"+��*��'� �S�!?Q�يx�u��.Q���t�F���*��U���;%�8��q�O^�la��r��H������W��F���W]]F/1z}�Bh(�^B��]FW�_F�1�xF: N�X��3�̰8�gęay��3�-�h�%Z<#� �t�E���D�-��=j_.��b�?@l����\aT÷��_Qe��(�����`(��7����^�!W�F�V*C���A��b9cwS/Ǟ76U�{.�������v^/Hjh9/5��(* �y�Z��|�\�Ҽ6��tc�Ej�-R4'�o^ϋyVwl� Q@� +��b~���Q:�޶i���,A��{�[[lդ� 8L%�t�]��U�Q��� V8O�s�e5��>��pm��� �-�=�@��%@��&��)}��س1|��F�y�'��p�o ����7+k�G����� �ANR ?I�RM�� ��J��ʮ��D�F棞�_v����Fx�e�,��~�C��M��}�'�>;27d�l3>�D�d3R/xbs�2����,PYj��6��3s�MV "�M�����2���hoH,�ܷ��/���� ��؈ �h����l����H�B~����A����{��_��̼Ԭ��mK��Y��_��p�gH/����9zΧ��x��y�/�x�E�1 +�0 �=�Ȩ������$����P����t�*ᝒ�ic_�V1l�*k�t�)��R�y��4�����E};#Jv��p��>uT]o�0}ϯ����@�=��V�(E�(*���L�.�R�-�)���>9_@H���>���{��V&�T!�F��Df'Q��z��5jIc�YB�D�c�����t}4�b������Kq����O�06B�>�_q�8��.�q���&8�y/�RhT��A���s����ӽv�j 4��{{� +�i/�b�� tVr��qjs�,�/tk_��ڨ�n��]��T�����]�(�eo)�a��"�(�}��c��ԃ�� tL�t��r�����`�Bj0��;�D���z���QD�b�x� +��qW�zǹ��� '�x�{6~|�5��o���P=7������-Ɩ��2���h4��Pk�@R�`�����'O��W��Z +M�xn}�?`���X��j���&Tv�x6.�0�&���kYSq;!��:.�6�"��<�-�F�������j����M+�b�y��)Ǹ����n�L��F�h��#x��Ry�|�u:��"�+%gs��8Bh7)4 g���y��g2u��� ܂�IPa��B`w,N���)�Yj�7�bLB-�fI�+ W���x>�+K���:�e�^,�9�y9�%\�d�EؕSY�a�&q�r�[��Rd|=�)R�`_E�܁P��64M�$�����U�w*۷��8�� g@�V|�!��+�ߚr=�lUcɱ�_��c5l _��]�<5�����h:�Y����h�&2��т����;{�?�ks�6�~�ތ;�|�%�n˖'vs��5�8�I����1 �hG���|$�Gnz�b��}b�͛t�B�~D8�Br�˅ܤ(` ��u��EJ|��5����=|��t2Qm�E?� �~\�~F�E���3��q#$Ƴ;�ї ��BP?�TםN�����eMP\��� /��)r <�Xr��, aI��4��e����G���T��>���6=HX��X1�u��GF9��@���.�ӄ�P�Jz�D������6] ��i�12�A��~�r?�/kF$M�d,��D��Ȓ,\�L�n&p�E�J8$r�Ҍ��@с�~Ǐ��]v:��Sx�L8�nPx +�r�L$� VޫTiQ�� K&�t'U��Q�������rD���J��$@�7,��lQV� ?aB�̗ne����4[�=C��&5@�2]�SsW�D���&%�|sl��Y1.1 C4PMi4j�� 욈 +��M���n�<�u�`!�<�;�9��4�Se?-���s$���&|���&6d�:9��(7 �� +G-��r!�^m��')�5F�[ +�M�x���nE1�z��L��tM1*���S� +HW��R��"&�_������>}�����pg�?�3ឝv�Nf�f'���+����DӢ���G�quu�ʹ�8:&�R&��9���&YQ"O9e�Q$����<ߪ�m�h)��y<��|ol<�F��*8�m�Q����#*����p��y/T�=S�#0�߇ K#�繖2�L�"Q�xE�b��[����j���<%\�G�J +�2Lj���N�Sx[�k���"��Է�$/B�Kb��؃�G4dDfk��@�w��׼BաG$������\���1�%���!v�S��m�Y֚a,��V��઒��-���=D:|��Cao�}�kF�J�����;VewGr�,���{�'���V<��2F��)z�J����u"$����F�K��M1� ��q�BBc�ĩ�B�~dq�-�I*�*�H�5�{ N"ʰiғ�p���~- + �J�q�Kg��$c��ɺp?6OT�O��,3��[�ƹ�v~��|nc*��N]-U��o�x���Ӆ� �mb��0���oFs(i�����������������ggg�n��\��?���`x� .�� /?]��:�<�\��0�`w�5��os=mmU�oŤ�BP=��F�{pcXkA�b�_'64AÅΑ4a��H܅�U�e���)�xI�\ЄY��g ��4[>��#Q�X�k"ֻ���Sl�)ܤ���꾷J��-��&�˸oUD^̯�x�ۧoe aɑ<5��`\���ި�)��V��W?1��K"$% �!c�܈�[Qn{�b�,�DH��.�6��?�N�r��r�%4n����nTSLn�'Pyp?��ё7�����&��xu(4�篏��Œ�8V��e�c������{c��?��Tn��aЀW�qr��V ļ9� +���M�\i��+6�-��P��;��|�Q��d������X��a�:U9��fހrp��2;���=m��yd-#Hn4o�� ��ɋ�H�4j���K��T����( �h!G�V�򑗰R�N%z��k�.Հh=_�f�]NW~%L8[��tm�TyV�B��.����I�#�?'��X�ϿfQ�z"�J��ÿ�{�P�t�e�pX90��s�eQ䘭<��/��>I߫�[��~p>��9�n�~ݍo9�`mNu�B�:N�a�i��5n�;m���3S�Һ�z2j<���Ë_#*Zn�΅� E&���Kܾ&�˛�����?h�:��v�����v��=i&��L��m�Y��_��X_Dp1ܷ�T�o���9 Ճ0�/�-�Z�T�����3�Z}����[R�v_py��M:��!��d����"�e׫q�����/�y4�n ��D25j�IFa��Ŷex)bq��*��0�]�x�R�[�Ms��B�*�tF;`��>��s:Wbj�-b�!�Vt���w�rtC���[u.,�x5J�TWo�[���c�p�'�-��v�]�=���IJ�4���0�4λǝ�{ѫԨ�]+m3>ʥ/�Su�z_�EH�ZE��^=R��>8�\;鶛Vh���4�;��J���bX��J����0+�O��-�~_T|�%2m����z����g�W��T�x��!�N�_�Qu����~/�Q�I�$�.r�Ci%&4r,����9�jݑi��H";���߷z�*�3���R�\7� v��ˈn�S��*�`mI����i8�#> �j�Ŭ�r���"ø�ˆ��n�`�"ckx��}�����p��ũ��E&���ؙT!eW��E3�/8[0V�6i>3h���#�hS���$d\�"��?�]�X�No`��`<b�%���s^!c��-%FO��>=OՑ��b�y ��E�nw o��5e�t��� �֩yFn���6��#ٚG ڟ0Z= ! �4�t�N��9z���קں��zP��~���o%��}9 &Xyo;k�^�t�����#�br��w�z�mǾ�;��!�jq(�F��T��I����|�|P�mP]kA |�_1��&$�5v�|��@)�>�ޞ�'��]$]�)�����S=I��A�ͧ�W��rTZ�+'��J�x�\��U� +?z6t� l�Q���>�Sy�Ij\�*`�.�w*���7�6Q�n��|���Kl���_h$��N�m�+���xO���w��z<�sQxO�Ɯ�J=(�zG���X��Ct.r��)�i?�>=<~�>NV���G�>Z��iF�{�>�be�DH��)�� q �1�Y@�R�f���z(b����C�4�����O�:6��Q�t9Rjf��Q�w/��� �R�Q6���*pi=��ῖѶ�,���6woM.V'���m�Ao1���+�!RwK��+Ɇ6%�J���8!�Y�ll�ؖg�i���ѦI"|�G�{���Mh�x�\�fg��>'�x[M�����n��s����"v�f)?ğ?8��a\`����]���� +���6������ܐ���O�s�T��d����s^�)�3�Nt���1C-�뽇��9��UPh�� ��פ.�+$�$�GǛ�������r1X�6VK� Z7����-6N-thEb� �Ė� +n�@k�D�� +���$����c�䂂��C+�k����?���Π�����K�`��r�ޡ���e�E��Q�"׳���]X�դx�]��Z�y�|���>�RYU'�'��o.0�7�L{=#9F���������)����I/�m�-�m��n�@��~�9p���J��D��T��@9EB���G]�ng�ШɻWkB{����~{�9TJ2��Q����9P�)|�o�� ��*��aK������ +��?=�D��:��n��Yt�I4��Ѽ8\_�4’ +����5$0���< o+t%X6�"�����B���`Ǵo���p���\$U��V���%�~�F��=k�Z��C`|I��Q氦��YA7Yf,�_�PIV����Ӡ]����.� ;�����E��H��F��w(�)B��*A�f�5ڷ�ݦ�l`�8�Z��ڴ��h��-����G� ��3a��h�(�t<>����������f�u0��8���s_���t�.� +��I8!m� ��m�P�ݸ��t:��}4���rb�x����a���?uQAn�0��s�A6���n�$H�E[ A.i`���E�&�%e�(�����ڊ�Q�ٙ�����=JV���E���;��~8�&� #<�:�҆�;��}9)F�<6P�fH�#ak|m���oO�Xs] C����ƍ&�} ��7�؜��+��� �(d��[����`���i�ް��Ș lk$&hg��� �n�����˶� SA�bbj�wŚ!�f +���!��������.Q�ı��T��ٴ�+$6���`[��V�*�v)�(hRJSX9VR�z���/M� ��tkM���D��Ȧ +Xn�Dſ� + X��#��I卥#��"j���-$��C��S��R�ѓ⋀E� ň�g��>�N�;g��V���mqS%Dɿ���&l����,c>�= c�'�Eq��h�f�*m��Ne�AI�q�b�n�%�Hf�i��"KQ��N�*���T�������7%�A��V̥D.��V'��T�~����;�:X��/������Dٲf�<43��ċ+i'M������e��_�������E�= �0�=��F��89t+ +N9��� G.����������R��\q�VŷW�(�.t:.s�){дr��D5)yp�G6�1�9J�*�`�c[��MJ&���$iDBnF{~���Eʱ +�0�=Oq���U�����SA����둻JE|w +]?��YG��X�ag�r�F':� \a�t���pG��y~�{n�C�p͙ +.�XYj�>x��8��;�Ƃ��4�H s�H��4}b=�&�jCi��;F�'�*���ۛ����zY��8F l����g3{l5F�b����J�E�ig2ѫ$� :�AM2Rw�2�k--ؿW�<����9�.ׁ�A�?f ���ѩfN�p|��ݿ�?}�Ao1���+�!�lTqm�ET���R4��Z8��UU�;�6�4|����o��M�#Z6���I���}�^׳j:�0�]o:�6!�(B��=�m���%��/+ ұ��V�X�;��L���"=��3��L��b���| g �İ� �#��_ :���[> �O��n��o +j�X{R(����&+�8X������ -� +����H�� +�U�q�Vٺ�3+�'%D�ŸTBϖS>d�9�p�J�}�3�tQ.J���^�(�R������k���7��JM�]N=��p�Se���N#�}.�8�6�3l��֨ ��O��3�Ԫ�!ܚD�{ w"��m��~�P���_kfk�"�3�g�ZٸU����&���|&a�l&���T�5gj)��Qi���L��� +M�D�\xBk����c�:��b�l�ڼL�=�*��bL�PH �DŽ +��_k��;��:M�s��w��Y󁋺Q8�j�t�/}��1���v�?N']���]=�m�vT�XS�7��fS��BeR��Q&�oQ#�'��{���Ӧ�1���S�q )�� �@�gs��`^�;�X**��+ha�O! Ƀ���_l�Ap>��v#[H��ծ����y ��KXn�^lv������_h��0�Oj*p�F_5i� ���;�*@�Zz�\N��&��s��۞\/mI��k����τ ��Nyt�>l���9��)}���XmS�6��_��p��ㅼp�\�L�2�%)�؛X�#�����{G��IJlG����g�]i��Q +!1�� +�i ��S�zp❶��[��"*`Bc* %\B2����dx�\Є�[�����9C8� ���%��ٸ���78&BR��W̐CW��(�$���� ٌQ�Du_2B�dq A�>q:�$BLd��I�gD҄B#s���o�?]\�\(Sy�2"���*|ƙ���@*TD��!HBT���HI�@��V!@�����>�� e�M��8�tN$�n��2k��\�U��/���y�Č���W�P�Z��� 2UXNjk�`��M6��Ǫ�!`�r��8����L$��oC"��O�qL�d,P���� aB�,��F{w� ��k�>���~��8����$��k螚���A��T���xie�dēW� ��c��JH�Y���4]��Z�3�pu�fA����U�DH}� ��CS��s�@����� �FJg6���p�gPM 2K޿k����u��k��X�����ɮ�z0)�LN�r�ǰ��9���:�)ʯ�m]/����� p\+�z��תa-�+q�U"ǎ֍��R�dF������ +�68����*��>֍��Fׁq�ĵ��}G�����X��<�Md���j�����=-5m�kP��X�� g��i8��~gg{{ �`o��kg��!��5�(���:r- y��%���D"������5��ok�����o+�KN�or��E����o�N�i�MN�O�66��c���9���ic�;k��1�z�-���������]-85G\yܔP ��n�qq�;�����eGmms�G4����֦^4�~mN�g>����W,����V�7�Wϡ� y� |�RR��~#�� %/[/ ���9?�Sw�7-���� �fE��n��WG ��L_��Fj�A�B�7�ds��m�u��s�dJ�(�E�pN�V���Vw̼񠗣TjץLz����7�3���y�meA �,�M=�B�t� +yo:#/_�v,���6Q�d� �!� �7�㘜�]b�*��1��� �|��Ψ�֦^FTn�z���lA��5���L[�{��C,<�8E��s��|P��\wsZ��w'���0��J�a���h\��*�ZN�Z5ό�S1�[�vM���A� q��$�� �Y�E�e�t��ް=P�:�����[�,��c��������Ag��xr6:��s�=z��ѫÔ��>'��,��]�����I�P�8��d�ɇb�Ҕv> +��D�$���npv���4��YZ�y57&�*��P����U]o�6}���<裎��&q7���i_,���+��Lr$7h��>P�e}ر� +0��x����Ë��%�H���F1j��G����;o���p3 K�I��mL�G|F����d[]��Pq�� ��2.��x5[�wC���gDF8��)*���W2�(d����Q����ޔ3c���,�!J������c���0�\#0 � � �� � ��׏ף��#*clbb`I4���3K ��d&cU�"U����' ԒP� t�jфh �����(¸�%J��o-���gO����J,5|�:�R(�a;�JQZ"9��=e:K�(����G�W����~ I��Y����Xn���B�+@�'ǃ7�>D$��vۥФ�C۪rr&x�>(��<�w^�[�Lo�p�eA �]�w? �����`�]����t}o��1��&P/ S 8.̭�� +�T���urЍ4?i��\(bw7�Tbm穗��r-&��z�Զ���9k�M�;��x#Q#TS�M��^�fw��vI�~&xC��� R9���r��7�P�wr���?��s͋�y�������V�L��i,���Ѭ�fΆ��T9d����u� +,8Sσ�N�mTo�Q:�ꐇ�J?����A/V���+��It���N[�Qͫ�eG9[����9I�V�ʽ���^��ծ�� �/u�:���ڮ�Ρ���~N�:���KK��h<�����kz�pU�m��L��Q��s�o�UM��0��WL�I(�l8Bӭ�^*u+�J\6(2fW�������|�*��yof��x�=Ň�H"ВJ0�|�+F .8���$D��<�%�V($���0h@����Sĥ�q�"A��������H�%�[nP�x��Ƃ�B� ɏH,�AƇBb�� +�-�}-6  ��� �$,�>�"��"C�Ǭ���i'��Q�%�*q�}�j�Pe�\e����w�����*y�'*��DH�U�*�4��\��W-�e�/�ފ��/9Ri��>��AZ���|U�yE�v�g�eMZ6�kܹ�;8��pf��ι��П3�"g��+i�<���1bۺO���[o�_���+X�/#�\1��w�TG�`�܇ȕ~=<�A�E�|0'��j ӋM�p��ϲ̖Ǥϓ�V5���چ'�Wv�́'AP*6����u�I����m��5�Ӓٹd.����#�G�YK��-oMc�v��E�W�V� �5d���ѱ��G]�g;��X���)4��[�alOk������ ��Wr���Ru�\P/�zQ�/���I%|�q@(ZW��zf���}4��ﵹ�7i�UD�Or4?ACt)�����y4��gow��WZM6R �*�s���}��jA ����!ۤ1��v�$�4PB!%�����ޡc͠�ؘ�w/��C0%s��Ӈ�ϯR�б �<ʦ����3�:�5�I� ~�>c��g$RC\�WOz�<�f������*��@��2����X_t|y�Gn)�'�.���cc���1>oX7[9a�x���ߣ�zƺ��A��7�tޱd��u�-��r��2c�y?�����{x����b�ɰ����|�b�aקּ�Tr,�.v\#�6B[Ή�4k(g��e۲�i`:�`�#ŕ���L�wd���³W2�6x�uW�j�d��l4 ��c<x}gu�/�C�w]�z����k9�����>����� H �S�����9l���zi��W_o�6ק�"N���I��s�M�� + �t���$GRq�"�} EQE;ي�M�u������쭨TX6Db�����C? +Tp���ͫ ^�mMli�@"5�-��D^�oׄ�-*�:˻��QһZC^�^2�ˆ�?QjgD2|���_Wx1�/�!JS��#�(�L��w��E�1�%ʻa,�mՆ���LK�i5�����K�5¶m(�����%2�@ٖ�є�9��B����r��V��_��zC�DÞ(���ta{�k��c���D(y��;o2Fv�)1��2�Z婿�T��o��1�G��eJ��?v��LiI(�7D*��m-��l�^�-+�b%$ez�̲�!JAo�lw��5%|�D�ih9��c�U�W��hN�o晙X��@:PN/�P�ǺACˋ��$5��s��(�^숸}�{-��))Y��yl��{�b\��T�C5��-8��ݑ:��iY�`��;����/���Xf#$��� �}���y��{!Zں�Lv�3���T���H����l4d��Y�����c#���OP]֐�z�Q�js6�ڸZ| �3���F����r�t��+^Y� C ��oWp��������PC� C`��S{�q,J߬4 � �>YL���,k\�VC7����p[42uԚ!��=staOO���P/���G�L�Bpi��mK?��9$���%G�>����uQ,��|5L� �3��K�0lY۷o,�z�-�H\�8Pk|'䴫�0���:b�U��� RU�嘞�<�8�BO��D�� m��Z]�yK�vE `m�LЋ�]c��̭}t�!rߧ�y��h�����]i �j��U6y����9�s!�Py2��� �G#1��Û0�fy9P;'&%F��B�+����x�����U���ױ��>2�;�� �?l�fgbn�[���I$����Y��;�����D�&��t|�K +oz�Ϙ����y'H���!kOV �B��(P��<�M�Q��`v�ZC��`n{0zʤ�M�?$C�������&0�^�~`��/����iT��&�� v� �h���]Y8+�x���E=vŁ+{v ����0�opI�)�?J�a��wG[k�X�?=��������Q����t �n� �}�N��^�M7V�����3�������)�œAo�@���s�]���&���VTjQ�rDB��8^��]͌I+�G�8N���؃�]�7������D��8d*D��������r�M�28�O���#�Y!�p� _�Ϸ�mM�� �ڋ�.�”��=��C��XN�=�-��IE�c���Z���:b8���Yl"���PxN�l��m�&)����l����*0hCPw΁@��YC^����6�1DG(�,�־��ˏ����: mPa����]T��j��б!0��>�i�%�h�0�y�u�мI��D�^�y��"������{���DQ��yk�u���%�m��� u� +i)?���bҎ=�V��}0]K^o1F�,�O[��_Z���l��q��g��YX�刎O��������=���R��0�a����z/�<6ȳ�4�ɮL �����uy��2���e@����H���w ��<�X6��������XKo�6��W������w��$N�h�H�&��]�4���H���E�{A��(Y�c'�.��y|���G��DB�# +m�̽y��a���to{p�P ��I������ķ����@N{.䳢�� +�Tq�3F�TF�QO���~��c��9ц�a� +�t�p"�B2l��zH �-ڌScI��"�������K��$��1�*�����F�|!TJ | �!���9����ŧ� +*��I��%�S]����$`�Ǵ�T���w�NRԒD����`��j�T� +��?��s��Q�rs�E�~���%�us���U��xd͆Hd%I�fͽ����^Entk_u�P"�vL���Dj�҉ΤT�5�P�)(0d��z#b��9ܢ���P���\�#Q5T�dw���� �RVQldsF#X)�N\R�A� ��{[�?��i�����a��j�>縹l�`r�A��5��ח�V8�v��!5��!��*�,En�й�# q|.�!������'�b����2ju��Yb:c� +\��4T�Wu�����gTa�G�)����}��a��X��E*��+v�&S���������4��^Q4ܾ�Uu�� 8.�4|*�ɱ��o0깏B����gT���\2���`4���>ƆE���Fc}����� �6��׉;���T(�pm���:M6������ +�:�vj�Ͳr�7 `��[nW�ި� G��:2��0�.��-�������������������o�~k��������9�:6��f���f�{�A+T�#�H�*��m3&*wϛ6����^ u���J���y�&�9z�ZI� � �����^�~�lv�B�|lj����i��:g��;k�v( +� �u�KKA ���+�"��]�ˊ *���dv�=馓q�ˬ/X�ԗJQ���4U�1���� +�q�; �{{x���Jb��Pu�w�E~�!���6�,��*�αwq^�q�H���aJU�l�34|��{^���������t�sI� ^p]����*>� m�z����w��\��RB� :�I"�1D�\{rɺ�����"���]/f����h�i�;r��Ј}��k�>6fy��s������P���&! �X� %i��j�Y}���a&!�Df�'�YN���"�Wgm�_H_�� ���>]�AKA ���+��J�xn�Z�XP�(Hv6� Ng�$k-���V�DŽ�%�ovQCE�>��Do/���8��h�&��x +Q��Ĉ�Jb(ɪ<�Q���8�ثR�_��ȏp)��H��XL1#�/ƪɆw�ؐ���7؈w�ј�FF� �9 J=[����f! �X�+%i��z�Y}���cf!�Df;��$q��H=�8�6��"H_���_�� �$q4g�-��t����u�OKA ���)�QEϭ��XP�(H:��g3�$k��V�P��KozZ���c��;�U�?�{a�1�v'�p/`��ZI 1���⾣:�O��Ҳ�A�����ʲs��]�We\$��n�RU>[l惆O��� 2R\��S�g�+�K�m���'�-vP�i��ի,��~�]� +���oБNY�!��ړK�}��d�W���w3���=��S�6�#NJ ���/n���cc��17���aP�� +E��o�`���R��.���go��fBLd�f=I�݂ߜ��퐾$%ß�>�u�OkA ���)�1 !�g�m��PC[ +io�"�j�"��A�� �߽�'`�QO�'=��c:΅�O����G# ���u���Tz��Hس��=�l��I>ŵ)㦐>��cI�|�9�8�=o�CH�'6,� \��qm�����H�G�3 +��j�l���/��!F?���t��dVg���F +�z�V���(���>�oW_�W�}1P`G�N��/sc^'ˌ\;~i�2)��2��Hir�Z�Hwm�id��S�6�Y�� ��V^w�`���f�� +ϒ�M�����e��JA E��w�"��ߎ(���$S���թ��v�ߥGGa\&��\���t �D�7̫D��†}�mN��V�:1��b(T��mG�2?^�J��;K�4��*ϝc#n�*�$��puÔ���|5�4|��{��������jqT�¹$^O�>����*>� m�z����O��\��RB�-:�I"�1D�\{rɺ�����*�X�.Og7����҆w�X����� �|4fy��s�?vv�R�V(�I�1�u�y���%&!�DfXqg9=���7gm�_җ�#k�[~����RMO�@��W�D�^HShP�BU�*B��8u�����^�qH>��3�ͼ}o���"B��ƞ(��;}�(p��q2�'Ї_ ��H V9�, _��K�)Gѣ�Y�OL�B�gS�����Y� {�.��GNp� #J��w���Xօi,"��px��,��;�ʓ�P0>�2-* ,�����B^9�Eh�vd� ��z1SF��wc�0�%�|��^:�Uޛ�ۙo�����e�_KA���Sԣ�(y�K⟜(h1�雭ug{��ޜ���^<�c��.j��c���?�K��#>.��Q�~ �ЧL$C��(=� �n��;����$`�^������8��8oJ\d�'67,�)�ֻ���c�s-�Iלذ��pV��R3�� ��QT��I��(D;Ģ��z����Ui��觜ߊ�tN�jDҾ�Q<=F�#~%n��ۛ������]�ql��%���6������E"������V%r�E��'�4r�Y��b3�/%N#��V�7|vjg��ƚ9; ����O� e�]KA E��W�G����MEAE�GA�٬�� ��U��.[�B}L87���Q� +��*o�W���� �ߞ��N�:1��b(T��mG�2?^�J��{+�,��*ϝc+n�*�4��puÌ���b=�5|��{^�������zq\�¹$�O�>����*>� m�z����O��\��RB�-:�I"�1D�\{rɺ�����*�\�.��7����ʆw�X����� ��|4fy��s�?v&A�g+y��4��w���<�\��b"3��y���6�/ ��7k�[~���]�QKBA���8�)b���%F�E`�B��sݥ�����T���4��9|3s����eX6� +_�o�C����鍪�~�>ޝ�>0� SQ�o��<�^(��E��4�}���2=<��x ?��`L%�d}����X�D=E֩4�>�r`Ɨ��ao1��^������:RlI`���b��W�Ij�a�d�h纊԰d2|�oTU&�N�"��2��]�N9Z���&n8��~W?�/u�OK$A ���)�QE�=ϸ:ʈ�"�Q�LUz:lu���e����<�嗗Ǜ�׾"q�����I�'�l8Ï�Y8= +8�C/�N2C ���t�멭��oR���$`�^���d�;�!M���77̩)_�?��?�q�k2R��� s�.j_�����%��@�{�� +҄Xԛ�G/�޳]��ݘ3�gЉ�Y�!ڕ6�K�c��d�g������jy{���vmxO�-���/N؊��1+c��X��s��J�����0c�ϔ%-�fX}��Naf!�Lf�-ˁ$/Rjl���8k�o C��3t��=;��7�pm���������N1���)N��M�z�ʏ��ԢJT�B�&�I�±]{6 ���7H����̜�g�g_}�Q�28����<{��Kg�����Uꈙ6 �)� ?K +���Y=�(�����A�KA�:� �qe�>r��3 +�/���i��=��h�����M�—��7�/��0_��{��jIR�-�������[� %cV���F+����̅�v�o�"c��n���^����iT���$�)��q��j-%$%]C���t���GO���fY�U�>�|� Q�p� ���̆Y� ňK�V �-3�w��XR@��d��>�% �(q �u���^ &�l�P)���F�iG�u�.xr�6V����M[�V������6��7�x�X����5�T�n��p���?�|?�5�S�̇�1��﹵Q�ؽ c'��N[~z����gΏ��C}x�k;�OK��jX�qk��f�b�'�>m򝶴�G������\��s�v:�ĩ rP��7J��#��18�qR��D[� �JJO�+�z0{R1֭�q,2OJ�c�(y-u���e�_r��V��5zϱ\j�X�Ғ�i�}n��5Lꀬ��<a0�b�Iut�=����iŏu~�]w}��L�Y�Y*����'B������Y������������W�˓u{�龇�({��5ʃ��ɞ���e��FڃY`e7Ō$S �*�v��~xe?�kXyo�$ivz6i~����lp�w�R�߂�-<�Z2�sB��O�!f��{;>D�H_�?}�Oo1���s� �5K(�*R[UJoU�wvת׶Ƴ���w��h��{����=���}��-2�����C^Ex�w�L�& +&�2 +c L��,� �Z!o����LAQ��ڵ/l�J`�ǰbG�h��$�sdG��p��i1�g�c�>RC �8�� +䃥K�#qY�s��IR@���N����l<�TEc-�SФ�F����k���%�C��ާ�����SB�Ӑ +�!7���F*�4������Og��j��_�T ־q�{KY{�1��UY2�(}�h�NA'y��l2��P, +ݚ:X��I�̍�骑��"�c�����R~�8E�^���h��=g�K��lIv�m#�V�]��^��F�y ����?���p�&�M�w�{��i�< ڬռ�!OweK&i؝����_#�$�.�������Ƽ'�g8���I(���u�q���J�a�z���wm���Ou��d��~��Oo1���)��B ���$(U�ڪRzK#d���������w��,�@J�fϛ�{~;��+j�� l�,d�1��w�٠�A~T&@i,� � ��W����WE�� 74ڙ�[6�J ��eB�����%�H1�t�?�8��.U�>cD�Q�_L}��y���;�U��N���$)(*@;6�(�C��c� +��ւ>Mjk4R@0T:��G=�U@X�4{_��o� մ!�ب� ;/,`c�I�Y#hW`�� #Uc�J�i�,�a.�J�SI�(�]�$t�0��U�}S{�5����Ȑ�n�T�'�O[�.f�Zlx{5�B��@�V��>>%Zx6k%W��av�7$gR�i�1�w��ǥ5��  �(G-�i܃W� ����q�N`|�'+�"�a���)��P�w>�ڙ�~��h��i8K��?F�Lg�����o����� ���"GGf$I�]I�ŵ�O�O���B��������Ao1�����C�F\IZB�"*A�T� )r��Y gl�lj*���v{Yy����o�:u �`�FY�;��S�����lb0���g�>|F���->vV���}KY� N�uLO�w�b��x#LX�_I4ca�i��� �N�H[��[�;*$X�a�L]��] +W$��e���Z����EV�ۢQr��6 +�#�%�3hU�3�seo�G�"��p�t<�{��{x��V�6�����h|��E �^;hm,�"��bC};3�vO9YG��͍)�<�L�}��?7��3V��@�:�Sdb�7��˃T �ՠ:N�V W5un~���h��Ӹl�wh �� 69���>��>=� 㞭~W���UX�7�ž�Y�g��~�;ˎ���i4~5��g���_��g��W��)����{6���A��0���s� vQ� KY�VEj�J�E�ę$V�O@���^9 t�,U}���{o�^������A�Q�J~��S�x7�'�I�V��6:�Gp9|-����g�:� w 4ڍ�'�E)0RcxdK�6hK���Uz��e���3�D���T�"�V��伡�pM\ThmO[[-Q +h3P� +�ǡ���1HI��ƀ��j��@�m�B��N��@p�tl�>m7O_��"����(p���ep�R�ĉW�"P.�n:��bE������IR����`jh�l�B����(� +��8���AE���r���ð~�Խ$�^Z�VLR�}��N1{3tAү��= 3�^���ײ�����|��V����x�OrAr~�ȿ�GΪ����Ե�.a^�߅�Oo�@���s���Z���R��*��4B���WYϮfg���w�ց��������{��㏾�P���������=����(�2����X�`x�n ?J�K��"�� 7�څ�{6�R����� an="K��b�Y~<�8���*�Q_0"�8_�|��y�M�yS)��6��$EhG�&��8�}v R"����_�&�5) Z;��G}�U@���s_����w� U�!�ة� �^X��H � .�FЮ�C;ÌT��+���FY�R��8էu$���v��d���L��V L�-VH^�Ɔ�?�TX,��d���U!@���Y��Ǒ'��'�ݷ�[����$��V �Uސ�Q��aHZC�S�;�w���5�_��v�����eN�wK��*��`������`�AiZ�NwT�N�d�*:��u�h[���h���9�s�?�D�n���t�mx9�#�U����.rtdF��jw܊z�p|�hI�[ޮ���y����Ak�@���mܘ^k;ubRjHK!=�x5���w��Y�P�ߋd)N���&��o�yZ|�uD�Ƒ�(�X�[}������M +L� �u �I�·�d~|!o+Nz]�e�!>��׊��V<�Α�ɢ ϫ]�~]�������<>sf�"�V����!xDz?��6{� +�%L�*v�5H��>�֌*;�"�����a}�@j��":��8Z>��6�����MTۆ֤8QBi�y�8Y��Mc)d1 J�ڙ��"�7/ +�(�K��� +~0�L�:��6kd�cӞOf-�IW�i^�y��r�w�wx�;g ����ۭ >�d��7��Qӗ�>m�Y7�USȻ��������Us��w�=�Y)����r1�,~ ��n�&���_����7m��n�0��z�=� n�^#;��*��(j#�ƚZYDi�X�r���^P�b�7-?�̎��lc�"��)u���+�a���fy2$0�e#�RHك��W�\��WԲ&����gc?Xn��`ƚ�I��C���5M��������5:/Q� +�0v���6��Ut >o�������=�u��]���0���J�8�����#��6�E/��U�����������碈R]�A;tPIw� +v�7�cc��TԷ3J4n�Yt�_�$�EX;/�|Y�^�����ٲX��r�w@���bO�j��$ +��b�R��`4��E��Lo�w[�-z�;�l��a��8K�V] §���������<�v��s.�*Y�=ۋ_�]���<^�oG@������ٚ�֟T?��K��n�<�Xe�Y]��s�i���J��jT�.ˉ�7lv�i�n�g�_�dc�������?�S�o�0�_qU�uPF��Vi�&��^&!ǹ��۳�04��>�%alyI��}ٞ|����Sώ$/yk��5�덓Q?�><�� �@�p ��/�p���g��@�W Խsc��V%C*{p�4­�;:�0N�,;�_�8�#f�3 1���?,�li�X���[t�Jh�� �8���9H��Q�8��vgp�P�@��nE�G ]W &�` +��&��s��狇�E����R0l����� s���11o����Og�hQ��Bb3�q�\}F����{����h�N��R �a�Q�`��=N�mQ����ꆐ)�P-#0,��n �Ӧ�� +�m���c|.� �o0��놵�@ 4t؉#/ݦV� /i�}+�W�98ݡ�K+�������"�3��{3��f���I��L�+�Ϫ��_۠hB$EvbH Z'���'ǡ!�� +��.�G ��0�c�&�F��IL1w´� �˚�ϱ��S ��:�u(,r�)�H��[���1�h;V�p\�'6 �Β�1��$���t1¿-�<�7Iv�B�s�HN �@��������ղ��mX� ���>{Q�C�V6��O��v��iv�N�7�*�*ڼ�i��]��.���������d��� J��R���g4g�s�����t�˨X�}b5鼍���?�I9ge���������-��z�h�vH���N��|�~u�Oo1���)ޡ�$*���?�FETTQ� )r����mfƉ*�$%�����{~Wos�ђNh�&�maO��x=�l��|�Y�q �";1��������ܑ�E�����$�� #?�;�����S\9�4[��-ݜ㑖N�]�*$��}a��L):oIVk�["[E�b �� /�%ѝ��I`=�+!���t`OQ �$kg��9r �� �v��x?���xWG iX� [�hY�hQ�-[��i*� >��Kg�D�&���a~�MS����D9��>OQMNJ��T������YXhM���������� f'8�Z�U" o��6't�,{t%� ? ���x����J]g5�W7G �O�ז��.VdG�����.dE�M�����]��NA �����x!I��hb�l�i\f�NWB��n�Ƕ_�?��&���}Cʽb*��m��� +��� x RPKÐ�LjH5��2�=R���]8�y�{�M0�|�����LH#Oק����!V��bB�ܲbRN�i�Sn���n���F�� +>ESY�����%�F�6 �Ўn�s, �u�-��8Dn� +�Kxw�{X�O�Ew�`�vTPI���vb�+�U��⣝�����󹿱s���f/�ي�����_}�Mo�0 ���<��i�]�4KtX�m�ݲ``d�&KE'���A��:�o_>|Ly�ї2R�AX+�-{O��0M&�F��rmt�,�r�^"/ݯ�huNA�h� ����R`���Ȗ�ɠ�C,�Ȗ���]F�1���h��jb����ܗ��7t|".*��,[[-1 +h3P� +�M-�C���1HI��ƀ:�ƴъl �6w\�hg�� a �j�5}_���o/��lCJ�a�L�ve��R�čW�"P.�n;��bE������IR������Pڼ.���cQ0(�q^[A�x�$���B�7(t�+o�"+�0�V�?�o���̢�2�N�jG�`G��%�%���[��X���1{�o�����i������0�=�I���Ng����ĵ�����N��&��l��̙�f{��'W� +�^8 ���̸� u�+^'���V#O[����+��Ђ�pi}���ˡ�vﷴBG���?��Mo1���+���|��*R[UMoi��w��k��1U��7�,%�����3~����Q�� LZ��`�ۃ��ɠ�J +P�A�^��+�G�x�~S� + r�A��:�aZ�-݆Ol����`���d��_�8��-.TR�`D�a�=L|��y���k�e��=�FK���l�YaZDq��>;)�h 藠ImH� d Ǖr� ޠ ++�u��u6��~{�P�6�Tk ���9�IJ����"k�r�n��YUa�J���Y�L��8Է"Z���v�&I�Ӂ�`��Q� Vh%�� �J�'���ue�L�Q!@�u�����,��Ԟ+�M��}⦪gZ)A���jd��d�H�]�z����}\үS���� ��N��wmo�s�~�7n�a�/( lh�u���4�k�y��V��c���΀V�P�Y8gF�l�p���o��|��$����L�rtdF+��X��̀w>�g�,����{y����t_��m�O��0���s�DtQ���nY�V�{��X5v�lCW߽r��[^~��7|��I-�:γ�>��59 �%�4A�E�J� ʡ�aK��O���¨���Oа϶~g��<:��1“�7�w64Z�� z�aN+��(c���Q]�dkM���z#��b�Q>����ƳZoٵ�^,�W�2h y +i�$GP���^Y�C�I8�VѮ�7�>O~�'Q�i�W�c' +�^T`�|s6�$H[P�N?1bC����˒$���2�-&���x6�:^L���,k~��Ș-�{�|+8K��sX����i��V0b*���q\�� +O� ���0 ++��Y6ϛ�ﴗ#�m�㹋�}z$�Ӓ�Խ ��Nõ�\`�ak�������N���l��� �R�4=�)F�b�s��m̴d=�#��-򱉓��\.���U�EU�s~�f�ޭ7�b8���e��4Aahw+kvB�������Ok1���)ޡ;� ��n'li� ��� +aV;��JB3�J�{����%������[L6�g�)�B4;���X����1� �3� QV�_-������X���N{�cv�U,������*XS|����=����;u� g�e�H6qL����ljB8Ж�JA���A���,3ۧ���1�a^@��;�A. 1O�.�$�$����;ߗ�����Q�5ԒbK���s��:�к�Ē �Ğ�uΚ@K"Ç����x������㪛��3�3��I1�LH���P��^��w�i � �-;/�E�*&�í0�.{�Mb������|���9i�Ւg�S#�L��+����#Y�=� �8و�s�P�$-�ѽ��E`�0���FG:�@���C���T�5�WŸD���o�ŏ��(�Mâ7l��O�{�zl�Eؘ��&�JO�t.�5i��N�:�W�m�Xd�iMl�3�� �����j[�04�MC!�I���KȚ0�6o�ɑ������+��N�@uG��n�W���}��jA���uXk�C��b; +1$&`a4[�2�3L�F��V��C�4�|U�]���e4����J�������x_ϫ�� +�x邢 ���!��޹�~|sZ��T8����%l;����T�XF'�XL�pE����7 ��̍S N�� :5r��r�9�d��N�$؈�I��J� �����9XG�C��EG:OQ"H�J�,$�B�tJ��t_W���huH�:g�9E�8� v�:ؘ���x§�o��V�zjv���ͫ�G��� M��#{����(&n��� �<�A��2��U�s�D�����*�ȣ�h4V� E ������ލ�^ߍc��BY�\�م�.ꓢ����k���Ak1����P�҄^k7Mb\hC!%�BkgwE�#�� %��ȱ[0�R�4|o��-��1�c��L�o��)��������_Ǡ�CdE�bH=��Tnӷ�$�g�s��J���a4���E7��S,�_m��/�p�R $�ȕ �z\�1sʑ��.�D"Gl�` I��J�TKE�nR������G��1xe�S��B�3�Ȥ����]���j}w�n�vm�H�-)��/���6�k�i��3|�x�΅�X3y>�oᜏ��U�r[G�X ��X:Ł<�9�u�G_�7i lw4�l��I�=�^a�E�ٽ�خm��@���ٝ�������.��߉Ǘ��+��7e��n1 ��z�9�� ���n�f�"ڢ@z �Z�W��H�nP�݋����I�>G��+CAG!y����`��VH�7��]_8\��}L��(^ �����S~��9��v�e�\�$��,4�"LxH���b��~u�_ut{�gZy���TI��C� �rIt +>��G�|�V�6���!d6��jYt��k�@�kJG��b VB�>��-f�DI��'�f;���]�x^NR�4l���WtQw���&���\%B�h�εc?��4��s!yU�y,��m�h$�6�Da2�kĝ����RW)��w�PE�m�|:S�OL%dUL�3jv���0���횬� ��5���ݽ�����j�@��z��P�҄^k'Ml\hC!!�B�F����;�kJ޽�#��P����|���O� ��8�\&���O�N���j^��8�}g�6!PT��;�7��7�pҳ{v��.ڶS���u�ґ�� ��W��~V��)�xCI- ����4�B�����cۓ�;�Ռ�����n�1�n�}�v�fp� �ig KbXi|�I��Sǔ������7����:�ڧ�)��P����kl�vМX�C4 �k�9/�zN� �7/ +�(%��(YIk�=��+K�0�S�Oa�8k� b�3Z�[깬>"+I;r�D�! +�e���-뵎��.gYnV�� O���?pL���V<>7���~�����>�c�*c�y�q��V�� �<@���Zu�����w�xj�U���T�}��j1������ݐ&��ib��@ +�Pd��%���lS��e׻.1Iu��o4�~Ϳ$�P� F��*��/�%���Oլ�8-p��g4>|F2�� �;#���a�P����i'~���p#LXÿI4cn��z=��k�:�#�MVoߨ#��gQ��W�˱K���1���MK9K��͊���W�Zb=+q�1�S�O�[o�tl{ilHo:uQF,��%^U�1���+�%��0������ׇ���6�K�C-ċ݃i�<1C�Iu��ٰ})���g?N�}_W��<���ݤ6~�[n/�_�T�n�0 }�WpX��iz��v]� +�v�Z`i(2 U$���C�}��ĩӋ�,^)����A�R ��3)�^9�p +��^t܉�w��)��<8A 6�߹�K{-����Qe����Y����A���< ��� �����(ų.��TxV��O,���׆s�;�Nc;�i6ƴb �8��0)Hk�Դ`K����p��Z�� �ZI4A���\��� N�� ��2��r0���R ��RxH��ja +K�9pP�ۂ$��)��GF��;!��_/� +�����P� ������ᒑ[�n� 2w+��փ\�V��02t�k��m�<�Zx߲{G�p֋��N��N �C5w)���W�� ۳М�z&!Jl�]�5V�/�������%�h0�ӑZF�36-Ws4�E�Ӕ�hg� +e�XWL��M�����3��-��*�+����&zx���S8鵝j�,q��qR�=U>�^�ظ�m�k���W1��q�V��S>8xƤ 򀫀tl �$�Fzg!�J��Z�.����k{9����Ke���mF�"�(��~�J�z�l����/i�Zǭj�njmo����Qf �̡�&�J���pT���xF�ͶZiLJ�9�%\���D>❬p��D��%>�R�.�,��'��m~4U I�����j�Z3���i�|��TK��]�MkA ���+�C!v���n>qi ��� +E����� #M�P���8v�M���.��ѱ�Tx�V�����Y��� w~�p��1(�A��R�#����;I�Y��a�ޥ�V�0f~��"��H�)�T��������<�� �q傥��y̜r�C��0��[%XCA��'���Rѝ��T`#��1��mt �EA�T&���92)�%�f��p�z|Z�S�4l$Æ]Џ_�al���4��>u�K�� M��<�p�GR���V�'�K��3��_��c�������&��/�ld�q� +[-�O���r`����O��gG��h��.��w�e�OO#1 �������XWZX���e�G$�f<�hS'��-��W�Bŧ��g�M~�������HMb�W{/���y3vg��x��ŋ!wx���ϱ#�S�5;��]�7�B�_„���/�)&^����iKW'x��W��qG��5�K_(�D�� �b�����[��&q^-�nw��� ]M a��@����˲�3��$�J�i�~��~:��4��iX� +�h�nfQ�U�6$��J ���6�3�~IZ|����΅�U1{�Y�%�MsJ�U@oF�*�+J���U�tC!�Qs��o�%dUL�/�h/u4���Ղl�1�Q�k����t���MkA ���+�C!vHz��|��RH����ݡ��A�� %���k'`�s��G�û�,}A�!���\c�G.l���Euv\���hhcbDC!u�_{һ��3Il���–]����0ǵ +�&��duÒT����O�8��dI��GV,m\��p.���n �v�� +�!�k�G�j;�۬�ю)!��Nt���Qڬy�r�����+�f;w�ZyXO��mxO� �hoq�M�>5fy����];g���V(�a�� +�̰~r�Y։OAcؓ��we�S hG �4:�۬��9&%�v���}T��I��E�~�;��F��Y��-�R�k�*�<։��Hx���R���Kk[1���gQ����M������vU(cݹ���#1�5%��ȱS0tS�4|s�q4��nj�}$�I1 �~�&s�{�������1�PЇ��Ԑz|Ioӏ�$��bg[�&卆a4L�W*��H��jsR����~��� �yI� >qeż��y̜r�C�uX��[%XCA��'1 �jI���cR���k�庶���F�>�,$9A�L��x�ݻ��Y|�_��m6�aM](/oq�u��+��g���s'����a3�|�Rp�b���b1�/c� +��~��@��<�*�)c`{�d�Lߡɰ��Q���7���b`����w��'G�㏦��³�W�7��_5�Mv�VMo�6��WLYH +�8�ڱ�&�EH�b�{(`���"J�*9Jbt�� J�-Ɏ�]�'k4��oFs�K�� ��`d�NsZha�8�p���� +� ,���Ș����gJ�h�,���F+#�A�c��(�k���h��%3 +���Y��<��YL�oX��K����@]H�;^�Y�L��o�9W`*��(I�}�(CHK)���:o)8*� T�M�Hh5�B"�O����/7���[��b�2F��,$�ֵ0�gA�c���p��� �r����o�E����'���í���cf�3[H��Rq�.��́�/�� Td{;��U��K.�\"3s4F�~��p���/-΅"4��ݎ�0BQ:.��А�P�E��������f0�0#*�h8,2f΄��r��Ë��pT�Ó�zb�ͭ��*�O���{w_�#�[\�����cǜ��x�l�)DG��h�\܏ܭ���\�/ � ���g/ +.���~� R]�$�v"����5X�5H�Q`Q���;�Cu�n�-=E;j�����+4|�䲶�'��0��=�Ȕ�:�=G�xst2��m85�����f�V���t*5K���E-�=����m����:v��3�D�y��3�:�����eK���\��*qj�M�O��d���,j٪��S�K�9�{�� �V�|^� Sr�� _��u�F���- �hc��A>� +lj�ji��b[�kK��� e�����L-8����j�Q�H<�׫�1 +�� ���.F�����Bً<���_�Rls�3�Fُ;��qc̘�.U";Z�m\!U������-]��CT���K7�pQ'�өD�� &� \���6��e7c��C [c|��~���x[];�'-�v���w�#�ϴfMꌫ�׍iΤ�Z ��� !|���z-���ʣu?3UÙ&`�Wh�h���y���d7_L���z �,�m���#�e�I:�yt��=Z�Su�B���9��>Zȅ�B-����&��k���oO�0���S�I�?��ut������\��Xs�ȾP���>9u�4�&�w���y�s{�!Os��Kf0�d�{��hag�8v��]*,$B" 93:��)3���-S"AK���+�o�X�!���(��d�'�pΌ‹U��8��W̒` +>c��mup��9�\b;p�f�1�Z���B���VdĪ m���I�!)�^u�RpTA�D���Ъ�Dfnʼ���b9w�J�2� � ���6�R G���p�c�t��bڜql�Aa>~��K�PѸ�/t�7����Pܹ��(��Z� +�t���J +�`X��7�%L���v4�)3����f>x68팃2{����3 [�#��F<0B8��nS�vy_J��S�(ReEަ[�Z�o`�(�����ф܁�5�H���c��M�Zñ���o�H�£}��4e�.�R��ܢ�� (ܴi�9��L�����[�ZN,(M`�@+�(��N����� W���3�`DG{'Ѹ�z�n�¨��M��k}��j�Jkـ���3-z�p\�BƳ�#P�����zc2�ؘ�Ï��v��ckWf� -�d4*_Yo_�?�Yx���V"BYb��Nn�s�:�z� � +��\��4��i�� ��P��=Ӂ���Ђ�,ߟJTkJa2�������]���^}q%������ð{�G�e��)� ���j1������uHz��4�qi� ��� +E�ήD�#���mJ޽�z퀛ҹ��f�O3��\BE6�L�h�V�.��>Lg��Y�3<:/�} xA2Yk�;�o��}M�v�.��)J;�Mf�"�EYs���ׇ����s<�ڈz��Je���p�\���� �Mk�O؎��( W��5�u�1���%f�#�]�Gў� �ssk�G>G +d���i3�}�]��V����bc��}U�xu��b�l 6V4^�`Ӓ$c��~������ޥU��XA[%������ԭ���;��.�'��#�ӏ腸Ѿ2i��z��W 鍎�O&tTN��Ó�l�y)�LqFVۃ��I��?s����*'����nHOV��������6o������P&^��LK�ّ=:�]�Oo1�����ݪ��J�R��"�#r����wl<����M�2�����~�>�#m�F��?t�Ip���\����A"!�-��c�m�O�,��D/ v�<�m k�h\�υ �h�'Lma�]�ˎn.�D++,�*L�и�>SʑN���`�O��AG�;��Zªj*���%�'�5F��Б�� !p��`5$�@�d��h���z?_<>-�S;7�[�� +� ooQ�MP�T�#���ޝ+�v ��ѩc\�"�F�j($�H��~+q'8�����bp�+�Q3֤˻�iڏX��������ys��n����5�܇�Ͷ�v��,�|��v�K_ͫ� U�]KBA���W��*�t��u�"�b�3�]Zw��9~��8������<�3��.�f�pO�x�z�,�7�� xw^�����LE�,�����DT)��t����D�c���ES*�g��<��n�oH�S� �\0�K0�.sʁ;k���M���Y�� +�1�6�{Go9 +��&�-�Oq�����?��.���jޝ:SG�= j/.����]yIm� ��K屉�e�dKGe�֧�L�i�:ZW���9r�P��|Љ16����I��s�A9ւk����uT�O�0~�_q�:�Teh�[�6!��$d�Ks�k{�KM���$uC�����w?}���J�F�Yiy��|���g'� �p_CE�� +��ۚ6�!��p�%Ъ�u��E�b���A�T�x���?�x1�%>*R�a�θ?���G� F ([�vV=6�w��.��Uc �A=� i��@�ra�����7�aC����,�~.���60����b(��ZX�I �g���]ه|�Y�F�J#��*ܸ_mF�Y�p��� �Y��Y��b��[{�n���Ⳡ-n,�2�?���L�p�Qa`-1lHc���>�F �D��ϳ�Я�yC�x��}�hH�\x�β�FK����p��Ut ~go`��cw�.�H{���������i��X�;dg6��OSN�K4���p��"�.�mVT@+��i6�p�x;�ۙ-��I��QB��@G�6nح�~q�z�����̋S�8*��&�� +�+��ŗho+�B�6/���>0/����r��!?��EE�\([R�9��D�0�d0NV^�&�g�5��*�ߥ��Ҷ��λ�ˏ�ނ� ��f��� �K dWyQc�q�7�l�a��t7��*{m��fo�4�kZ���t{1�K�ʬ���> 3�p�5U��P�`�_<�����KQ�k��QF�Ђw�'���84XR���3ֽI�m·�Jػ�(f ØA�`��U�=L۱�������uRMoA ���)��W ��)j#�CHh�����Όl/U���,�M��?���<y��U�m2Z�r��:�d�M� /�aȌE0 A����97;�'P!f>�ls����r_�r�H�0V�p���~��,q�X�r�K$s��<�#�KA{'d6�x���GO 9BVZ ����ht�`\�Pb��A��agp_�=-f��ylU �\ �Cj�8 S��A�x�%i��Z� q�@J#<�~Umd�$%7�Gcqy`�b��j�t�D3�%���f���f�(�Kg�ef �GХ Ǣ��N�M�.Lw�����L �S���{z5n{A�/7�h�J���`��ޱP��]�Y��b���F��V[�U��V��ϸ���@'�³sF�(ڢ4��V� Z�a�\wV�Nf���T V�N��K���w䯉�b�5�[�z�'�Ӏ��~ �}�[���3iw�P���$wk��$^{�N����ww�z�[��TKo7�ﯘ*�+H1z���]�N\����Asg�lV�ffV�P���>�zH��� ��}���ߪ�� u�c2Z�eW!�If��8�1|* CnJ�P)p9<f�o"/�ڑY�N��,�沈����J�����&�tK|Q,FYx�5\q'��� +]U��f��2/�8�6��#�!��tݿ.�F����J���JT��1� v������U&��*��p 3�)@2pE�J> �ۯ+/n��v�J��Ъ^��#m��Δ�ܱ�:}��_Hl�����,���E�4�"]*fX�u�i��1���r<��"X��ްxp^W��(A�^7�U�R�G���C�ZK<�44Mڐ~�<��t���Q��5�l,�pM(5Y��_jd�̳��Ԫ/�&��-��L�9�X��n)�$ɯ���n�h�s����l/��0�[��qҒ�W��. n��P<C��i�F��3��>����F��vG���*��f��gX����w�� + ��#;��%��4����i��=�8��S��45��u��ڜz���L�dG�_A+�?ӷ��d��2��#�h�m�D�ܵT_��:���49�?�<���հp���IAn���ԉO��+�XV�Mn0k��� �C�B���i��T�R��U�$�0�l�;���������=�)���$��YA+�&�B�mH��LS��[�;R+OD|њy4y+<���C�8 �@��{�nuk?�?���{�'�c{����c`�����Bן���G_��}Q�n�0��+搃l�1z�u�H�� ���M�"�I�+�A�/(K��$卻3��\ᐑ��S�+�[~q�F�d6N0�c�r� *� ϰ9� U�u����ū炑�>{C����M��Z��uF� h'+apKy,B7X�‘u�"�d�ְW�����7��!���<�G�V�L (�[_ +V�L�4�@������͏���T� �؋�L��e�+.�1|���i�.�,1����$���٧��y�H-B�W�E�yc�2�R��T�ဍVO��o���Zx�"�5�v�wÈ� +����5��S:��ڪ�´ʑ�^�� +���NG�)�M:]�T���'��9'9$�����}H�m�Ok1���)�!�Ibz���6���Rz +�Y�l$*KbF�&�|�"�I]�4����iq�lB�Ɠ�D�8���9�^����lZa��)z�N�H2b�{�F���s41=�{�S��GO�KV,H��������%͎������d��A���!�k�E��Q�-���y��w��2\�l(�.�<�2F����׻����m��˖2����Y�a�E.�5b&v�ʳ*І5�a�[������yUO���= >7q���51�� �+�M�X�$h�{��� �$-�)3Όwi^핡�Π�)c��&�2�<9 :٬�r�J���_��B���m�%�ɢ.��{R�G�?�΃��)�KKz�:�!����R��V�n�6��W̡E�Z'E�C(�41���S�b�4�S�3ܵ���^ E�jk��K�<>μy�(nشX�����;����ָ����^W����pkB{��w�UQ�O��_� +`S������  T��z�J{h�6`%FxVcc��W���:�x>Cy*�@m@� �[OC�^N���2�1X�BcBM{��ԬD�LHWEѡ2�O�A:ˠ�@Q�(`| �`E�wؒ_�th!��$�Y�e�]j���/�`�5� E_����Շ�?�m>��ۻ�� +y��;ų��8�e)&�(����^'��cpp���^��2�+ �2��6)CgԖ%�m�� ��U���6�0��.$��ܱ����}g �V����h'·@_��3]w����)Г��][�����A�Z9t�9[�C7�3�R�`.�c�*�,�\٣  + ���`��U4�OU� ���>�8�Z�Y5�c﬿�P�BMc�,�SGFA�90�)ō���{t#�+ڀ ����Y�-��CQ7e)�����^y�L]zQѩ ����R�t�N�6D����G^��u�ō`u[Q���1���Ϝkx�Ӌ���h�o1����@����ȷ +�oϲ� +��t�p�_<|�!`c΀q0���#$[;�TC���TRF϶�Xo~��Gc4$}&����1��g#̋�/L~��V�����@-�c�"��>�:Ġ� ߢCA�>�'�����)\���i���!�ޔ�(�����?��u��f�v�D��T� �^zF�e�Q��S��C����3 �F��ao��-B"� ]3Y|�s��@rN%��;�d��uʻ��&J7��M@M5�o��7��a�vg�w�C���E^���N�TrQ���vv�NOs;sx����Z�1�v���!�_�RJ>!�f���`j�!�TXҡ ��g0U 洃����Ɣ`�s�A�E[Q?y��I͞c������Sck�m����Jx�_���0��\,j�Jz���t����;�&�Ӷ��Z����Y�wߘ������֝����,P�{h�h�Z��sJ%���0*@dG�q�Fl`�SS��X��� �N���U?� xZ����-�t��t~�T�Y�����^^]�s�"��,G�ŋ*W_�Mo�Yj���c|�U3M���Ѳ��mR�n�0��+�� /�^��u�]��GM�-"I�#�A�/(�Qy�̼m��GW:$���Jr�/���}6J��]�.U�Fi� +p�3��R�h����[��նd�2�'o��0��9`,����t4���"�T��8� +3W:�NS�0�5�պf��Q��������<��i�$�@Pfc}%XYӃ�$a�h��=�?��� ƥ`�E@��A� +���>��K���)�01����$,K�����(I�}��|K��d8�n��}��i!#TjH�����FUNS��k�:��&0�v1� ���)oM���b�y�L��Ko���"�Ϛ]�F٦|�z�����c�����^K_k��ُt��w<�q����7fߌ8���a����'�!Y3���*����t��w� �7�y*���m��y��wz�N;^�%n������4kC[_&��/���t�%i7��Nv��0��ʬ�ݹ��V��E�AO[A ���+��8'P�(���*�T9�~�ž�j�G@���)G�����rC�X��y�����]_�.��Y��) 14������J�[���8����+�[���� K�ow��"��9�yG�B�y⎥�ۖk+<A5!j�.�ɵۿ�;����R����"��1��Gr�z�V���"�?��ج�?����gr�ɐ��fq�^<�gxөGF�tD� �F�F����7�xhdB,d�M5�RV:�T�J� O���m~��\���S�����S��M�"q����M�iwNۮ�Q �q�����Oo�@���s�d�L�^�iQڢVm�T� 뱽ʲ����(߽��@�?s����޼��U���C��([�w��$�����$��VY��:+�Bו}��Zb�mY)�L޲'x��������b�}��8�Z��E�&���������9��������|�"(j��t� ��!/����6� �#�K���������U3�]L+TX�@ne�E9��V���j6&仕��K����B��Y��0Iji|y�(��wȌ�a����M��} O�n�ң��8��E�k=*�\`��� � g͋"ӏ�2�wt�椾�W!6?���m_6Ť5���m� nSE.I� R�ZtP�rpOkI�(���S��� J���sR�~�a忶#��?�V�X��k4�S���C�i��6�?"7�9dK�~;�\�(M �Ϙ��c��p�� CC���%]�ZH�+�($��2e �B��f4@�(_ +M�C(�{����xry51�2��hx +B�6�0��W���J�2@D�u���I�*!�tE乸�"2�tRe(��0�:�4��^���_�ߧ�����2�1 �rm}�s��L<�����\%��L�ꏔ��Zi�o?P��r]#�l�3z;qLx�%1���{��[���� +~{������# ��I8�N��3��D*�N��RpΕ&��Ό_�����=�`���4x��D�{����ѰS��"�g�r�6cR;��'��J�c�����6#2B] w!��lH�N�\X�. �L�ϳ�i����<Րt��_�Z�[��tU/�n�-�x���9|�隢;<)A��3*L�u��6nc� KU 6����j��0?�o���^I񠠥6�d���șj �@�t�/��n�� ������G�N%w��$B��{O�*=��Z�xS�;Z����4����t�V2W�i%��*M!5���e3�y$���)*�1���)Lk��@J�$-p�u���LF��jlf���h4�׻�Pg�>J׻�^�V�njn P������, gb��8��U��k���"j���4Ɖ�D�{�5.� �,0P]sE#^ �s�f�I&�0�%����]���R'���iE��D����n�%�K!��"�꽵���(�5o�D�2S�ƴ�M���"?�|x�$�PW�S�*��>���8>ԣ��(�������K�ҳ]�7��5z��b,���3���}�nc�*7&��,�?~4��jsXc�]�Y4Q�t�]%R�V��� +�F��DFY͖�=�p����R��!t)����/%DrYO*�Է��̉k���%� +Y���%�-���u��y2��ۉx��OoL8���R���ϳ�� +��^��%�}v� *y5�B�@0��JYl��f�Ѣkl?mڎɨz����v^����;\ �N��z~��\iIydվ��G@�Ёl�ʔ�k��r9�zG7����Q�_���m�u%vE��2�g���n�^ݎ��w��㐧nv۶�7��۶�ub�sZ�����$��6�͝+�ڢ�3!\s��}���XB�6 C�Gc�����U��7n;������^0me���b���m�y�]�����Xه�"�`�oNY��[Iu�8֦K��]9k���ٕۙȱbY�W\���~W�ջՓf�z��䓈5�Iu�q��=7���*7Cχ/�O'��;�1�v�N�(�O�k|�n? g��?v��VMo�0 ��Wp@��E�nצ��e-V�(��v(P�2 �%M��C�� Kv��K�#������H9���Ov��,>$���8�cxș��qf@mAfp��-����XI��l�[�i�Z |�D�Dm �-��}��rk|&�2"� ���ܴ*W(GgD�@���=�Vj���l������;k�( +��D&uA,�b�#1[�����fuu��rP1� ;b e���)���:�F��"P���O#A +4�P�����XUdE�鎮���X,?3��J���b�~:�yQN��a,�|%���b��X��V�=��"���c��8�����e댔f[b�hu<�&]ר���ȉyס�W�U���:b_�H�E��،�*��ȫr�|Ms����3 +Y)�S�����ڸ2p�dQ�*�B�6�pow���m���hTI��{�\Ý,���CX���~��0*p&X#�r�m�}"���eZ����'g��,��A�̓��Cm����I����I�y�"S����������G��$��C����.� �іZ�[$��i�>����K����6���J�O�p�t�P�)���Gl溾��?4C5�������3�ToR�e u��B�:��q�q+�OL��6�[C��R'�Lj���-�o°��VX��K�g0�sFl�%�a�=݃vNΠ�>��Vi�7'�V�:v.�V��5>�۳u�t�t_nqG�+�K���AO�0���O�CRؽR��V� �H�X �΄X8�eOZ*���rHۤ�Jln���͌s�Õ9I-<������+G��{6J. x.U@�4A8���S�t��QL�[y�Z2R����O-�y����|s>�i<Ĕ�"���&��� ܸґu����ְW���/��%����ܺG�V�L (SX_ V� �4�@X(Z6y�����],�4ƥ`,E@�§�X*.���`k/ �曖/#* +NH�S)���5%I"����ֆG�X��GI"�*��VUDW��T�ဉV�M�#���7 �1m`BL���y�L8 ��Q��4m�Э`?/����Շi� � ��k%w]��Hk�Zr���2{T=�a׸u��Q��4.�l�)\� `O�-����ğ�m�z�k<��wL�$k�4��ª� �X�j%§�!�����U�Y;���i��^� c|���l����9=��fD�@S�ey3vi�+[{�U`�.g�$+�2[�>�N�N���<��\Yx +V/(���X�?ڬ���-o�ث%�+��D�{�r���,����,���m�GQ���6��.m��~�6�N�UPMO[A �ﯘ[�@�6�mQ����T���/�겻��Q���5��O�x��x񡆊�}"ᩚDo�mWY/��������!*��QQI ��}��|�02���$n�a�g��̸I����bA��j}��:�<��I-R�gX��pUC�R7"(w�%���`Et/��,0�!%��zc��9+#��Y,�51)�9�v��z����p�V��,�aK�.�-`ͼ�A<×�`��ezb����䮬Ə̝�-�Z���ę�Ҳd��;���[��a��q�o����J1���~Ⱦ�†�K.����R��� ��'Z� ?�@��٠\\b��c��|L_ݫ��T]o�0 |��������^�&m�uX�}a�֢Pd:�H�H'���A��v6L/���㑢|q� +J-<&�^I~�_i�:�F�FpW(�\iE��g�9|-��"� �~y�.�µ7o�0?�3����V��Y��1,q%��0�K�pA���+Z�1A� �5�ժd�I��z�!/�y��ZI4��Ln�F��f N� ���]��x����� RUa\�� �չ0���8O��A�l_�yd�� �����W�FQI���!3���p>��]��B���5d5މ�L�|Rk/v� ���ӸA�5����G#�� +�#-���:� ��V0‰����%5�~)ٕ< �*�'Թ�5K�[%q@���@� #�R����<�Mՙ�ډk7 ��/WZɶ����b_JNj ����͸��5��R����iHu�6W�I��ɼ>�v����}S:l[�T;{���Ӱ}��� �P��I��Ve�*���dN��-YpII�-��qpH!��J&�5�wB� J��K�/���!���1�W.��i3H��[�B�t� ���Wp(���̥0� +>8��� �l�sZaO�g@M�O�̍�����B����f�_S�E(|+�)�-��{��E�}���ǿ���v�\#wn+I���<����&�W�w����%-�+�N��x�қV�>if?�׼��\k��c^nMn��s�ħ�N +�EX!Ȭ��x�f���W���K�)�7�i����m�Ok1���)����Ibz����@��c��jg-QY�Y�P�݋�vhuͼ�==-?$�б����V��ݻ颚�*���:A�<� eE��h݁o+��&���vVQ�)>����)�⬂%����r��xu� �$�(� ���Kc�l�<!(t01hv��1���s�P���a^݋�;�A.�1�I] �H�I��q��Cs�}s_Pc0��8��sr��G�Z�K�a��]"ϫ@{�D��h)?ħ�GUe<����eRn�~O�kb���+��fX(����G*/�B,��݁�11ޝG��4Z� �!���vkb̓��-hO���VΤ��Y�e��U�U/�7�%���G�CͬC��oV��T�W2n_M/6/�E��NA���uB �AE F�$x$1�L/�qvf2��O��nE�]��ꯧ��g8�������Lr{ӟT�A��= jdS����FΎyʧ�;���>J$<?��`jJ���2�� ���e�L-L�"̲ϔr��l�Zx�j*�W�� +��6�����R�:��(�8Dd��g:�s/���u��V������o9X=����K��]��U4 I6���,����IU�`D�֪3Jn�bͻ��R�N��l�79PCQW���~�Q�n1��+怴I���$��*P�h�".M��޷Y�6��M����v��z�<3�͌={ۈ���L�$l���m�4;����|omBc�&D͂�ඵOt��+��l��`d�xϞ��i��Xf�=]V��iM�Q��X��21fi\�6R��:!��a��U��i0�������S;k�'��M���ёN�'K�~��uy���[��V �:��i�E5�VZHW>�̆`B��|��^Q��n[��aѿ�T����E���yb����62U�8�n��Z�p�F�� �r<+��r֠��t���;[��C���<�ě;r|�*7Lv�I2�=��|�"d�Y�i/zQ;B��0Z�|�a�o��4�C3������;�c +�0�@�XL����u\On�&�d=���Q��g�X�����C�>����_���Ok1���Sd�$1�֎��84�$��C���Y�ZY��7���w1%�褝��{�N?��C��ȀqЊ�|�H�������6�����Jx���4 �Ao+�L��%X��F���`*������*pv+�Hb--|È������4����7�]�x�p�PFc@�i�h���-]�I��^�7( a��n���],�V�$��J2Ԓ��Բ��Zs�“�A!(W������� +ᡒ��=5��X��Wb�5��d"�2��#��X8[�-����{`a�ӽO�)�R����p���D��1ZA�JeX����!*Ά*���C�s��]κ\�S����{|t)P���sf �c�'ʗ�JRk$;w�}���MF;�/-q����K�>t���a�t� +����җ� +;Sw�C��C"<�8�L�G����ȧ�ߎ\K����}�V����i��3��ޙ��/��X[O9~ϯ8Qe�h�V�IKS����Hز������=k{h�_�s�\Q�y���������qC�#=�% �\?Ũ�w����nvaQ ����H b]�^,�D�O�.# ^Ї#�>2��� +����>�� q<�)��)���p��q��B <�@p-�}��T���B�� c� 5�r�@�B��T�� �BXS|�|�'���e���@�T��0��#��y% "�]��p�B��""�D�ZD:�DJ�4|����/.�g����'g���Hx`̂@$\�֌9�8�s�5r�j�+��ȍ)�K��"]�t���� +\#o'��NW���3cu��Rp��h 'b�2`�U��Q����v�ww�Ú�4�Wl"��. 8f;�tM4�N\�>�T����Dljn0 +�\g��TC��%*��(�(�4��%MS�͊)2 �� ^�m��J�Z���9N� �`��6Edh�&�&`��ኇ��O��z�ja��Ȑ�g�6�Sñ� �:�5�\{�껠6$W��yScHm� C�/MB_�"C��(|� ���G�4t� �s=y�2��+�C�DG��*��M?�� �Z �Y�L|� ��GŃ�:�ɣ�7?�:��D�ӎl. �#ʅ*��� +DJ�TB���|�ؽ��µ��oz��_�PfzK��.���zŶSy�b�ilc�0��flK�-�#�Q������M_J�����L�+X������ ����sŻ靑����2~Ll�#�k�z•&�ah>�ք2�ֻssv!$� �� +v�k�Ԭ�?�0��Me�X����޽����Ai�*Z�����nUh�6�K6ͫ}���ބep.�]*�l��{\��-��oT�jQ=����͢jo� yY�i#H3��'S[}��k l������S^�ܤa=�&��;�1UE65+8��k�<��o�� LaK [s)5)�JR��,��Ke�f�Ҕ�9Z���u-�6�8����?Qi�̓i��U"���*�\��˛W��̣���[�-\��U�]KBA���W��)�t��u�"�b�3�]Zw��9~��8������<�3y(��&-Ӎ(��z,$w���� ���AЄH�bY�,|����DT�9l�����ȉ�m�"V��r���2k�`Ik+l�+�Ę�%�_(�H�j���ú��r>g�zB���o��%!��d�Z 9 P"Y!��O{o�j���u�N��[�� +� .���]y�-;������$�%)���<�N��u��bX�P"���I�cc\�"X���s:(�Zp�����_�R�n�@��+�@�D�BӢTE�RԴ=E������]��BQſWk 1�CG>xfߛ��ړ��P���0g!��E���m1�n� �{m*c CP$�+X�f�7���[2�Z �| ���*� I&��/�M��<�R���3F$��ap�>XL@P�흐YF�ĝ�'O 5B�}TOhk4:F0���(1ލ XT��6�iy_泇ǧ��� &��(���^ K��ARx��4���!�m�T��FXԊ�����q�EN��N�����j�e�*fXDZ��7M�j�`�A' 3k��?��p�kE��o�JƶI82k%��و��8;���_��(g$ߎ;B�Kk���� E-y Hu�'::"zr�����Ҥ��������4�?���vr�j:�����7�(��`�Mٓ�<��5�g��+�.2�)$�(�A�����?��x���IȸU^�m8��n`�}�]�UP�NA ��W�[�@�6�Dբ­�*g֛1��ބ��߫�&���~~����K� +����j���]a��4�����tAц��Bb�-����3��1�e'a��~�kI��H��3��W�C}���)�yIj��g�L�U� +��A����$,{ˢ{��Y`��c�?�Wv ��2Bj���BN�(�I���a�������m]5�� [R4A�kq�m�V�k��3|n��]�5k!�x�H�b��Թ^?B�y �;N,�9���9I?y�7�G�oƩQ|$��"��׻�>�j +�ǔ��G���'�A"��O��^~��U�K�#\\b�{��C����?�T]k�H}ׯ8 -�����M�MkR(iHv�]���J*� �a'���2#�և�]�Ϝ{�=���]i��kf(���܋&{�!;O�N���JX�& ͌�*pW� -D�J�#��!�>I�T3�����`F��z���r�Z3���B� .���JW���)�d��3b�2�#�� \E(|]������%Y(�0'��C��,a#h�ެ�o�C�(�U�a�,ra[.ʱ�� ����w�����q�]�̍z���'��a.�3�6B��O��a�{*���I��]� �4߼��M�T<�2� ���o��ׇ����NV?��N�ը�`�4ґ��AeMt����v��Z��Ҟ�����]���[�l��A�0=o;3��G�͇��m�aY�� )>]���qy�����2��*�}w!��Ȼ�cT0� +�����陸w�f�c�D��#���[ߗ�eI.,�5�f]��# +���p��� 5il��M����B���}V^��Ϝt/�> �����{���ʡ�ȳxn�9�Z'd������z=�������������zX�n��(��^����tO�������G7�P�����b!����� 1PF�v�����0x������e�e{��Hc'b���܈�Xq߃��3!\�� /�y�U�{#g}Ί�Hh[�I����}�'����D�Q��]����,���L�x��Ytڛ�gp +�Bx�-�q�v1�囬�?P�\��vx2yg^���'}R�o�0�_q<@D��:(�˨V���G$d�Kbͱ������CHiG�'���|������2�p��� <��ϣ��$x)u�\�Kbp9<�z�������d�ܒE�f����f�,.���u��1�p+ki��H0 ���/=:o0��(g���fG��s\"�1�:�Xm�B��U���c�e@�i�7���t��ZF�&��a/d:�0���8��&��\v�<VV�TO��{�n:2��՝6�:�j�]*vt� +�� ��r;L]UI���満?`�$��I����O#�(�<�d��2�}����Ir'���dG��Ų���[��UQ6�l`��] �q3�S��Q��_������4���#�/[�^NX �0}��p旐k��7q5�����$I�� ,�$���Ѷb�[a�kK'}���=� +��8¶�u�����-u����:��/U�]KBA���W��*�t��u�"$�b�3�]Zw��9~��8������<�3��.�f�pO�x�z�,7��� xw^�����LE�,������R>��=��}���@� +&T"O������!��&QO��r�D��4��)�@P�aS��׭�"'�c*P�h�`����( �T6�>�!r`�����2�f��Yw�XL)v$������Ϋ�v�%��2l�ϕG&҆%�e,�yZ?26���hU�z�ȅB���^���@"xca=��r��,�͏��T�N�@��+ !;J@�6�T� +!h�C���z�X�v֡V���Nb;�{�����7c���-�(�p�w$��W��S2�.F��{N )b��y0<���j�����*��n�F�UB��� ��i�^��S�����= _�D��۸��Ec ��4�;Z��8� +>>G�J�@��Z�D��3� +���1X��ք5�������>����\x� )q��)|�����lJ'�Iw�/"- +d+$�s.ܣy�;2����/-�2�^�D5�"�3� ����^�� + Ԟa��m��7���z-\�27:�U��h-<©���Q����*D��(�sxH��krFgGP��}u��� 7��,=��gXJ��"��|]�����¢ �^��,|�q���@�� +���F۴j�q(d���6���`L�����C���>>ne��i�;��9�޸*��4��yz���U� ��������ֵ�D�q2�%�w%5%��g#]�w��7o`Ɠ5��R������¯��|2�L(��,��&��PMo1��x�vWmW҆�U�T�c������myf"����ٴ����y��cn>Fђv*Qɒ���"���jZL�5~��#XFTI:����� ���J]a�<�S�%aܨ�i�>��[�]�֊�*�/�S� ��h"��(�| �$��%$ ?�1��w��=����`}�V� �ёb���~����Y~{Xf���%�+Fk��E-�V $���'MС=U�^m��҄{��]x62- +�3~�4a�U�m��� +��5�;��8��=�|��2��)!\hgGhZ�~��F�{��X�t�,��R� ���F�|.r��� ���&�����Q�pV1qY}�:w&�H���տ�mHi�o�Kz/e�޽r���Q��\L +{�2nmTZ��4�F��͐��%�JI�7%��)�S��W[o�6~��8RX2�d{(4���K��$E� F:��R$G������d��� ��!�y.<�w>^��7]h�1�`b���VTk��_����dxWp k.�� �Z�m��x>�T�6|S$Y +/�Dx)����,��������L�����z��f��}O:bz]�a��£o��M�5Ћ|��QV@�M��q���� �_.g�5d]�L2�p��ڳ���������h-�`��y몼i�y���6�w/t4�e�5$h���+��bm�eh����\�r ���O���8��'��&I�-�W��d�X&pE�Q; �a�u �%���Ht�hh��m����*��u�������S��ce���8�>�l�y����}�?=lXд��DRd~O�U+�L�~r��:�I� + +����-��6��/� n�`�Sɴ����ZZ6q������+� ��������R�ޞ��~�H��c��q�*��q����T�)���ӧ?d�>"<�� �=����'(����w��|�l�Dk�Tۣu�Ğ����n�>��UP�n1 ��+�v`$�v���A�6�s����r#!�$��8F�/v0O��P��Ⲇ��}"ቚDomWY�?M������!*��QQI ��]�/|�0*���$>��O�E2�k���b�I��~>m�b�oH-R�w�Y��=pUC�RBPn�K6��ފ��"�������:E�Y1wE��b�3�Ĥ����q�������zxj f� [R�Q߽��6Z� �������g.�3k%ϸ $�e=^d�\���z����3 �e�Ư6w�'R�����8��c)�9�R����~�G��l��:�:�~���cc(a�%�� �tE<78�@�5�c�z F���g>�o����S�o�0��x�JDA���u�VC��j�X)2� y±�����'C���vX�Cl�ߧ��'_z�QŘaҒ��c}h�~'�<�� �@�bW�CIk�%���8�eZ��n�g�_��+d 0Tl�fq\�rwa� ����X#�07n|��y�q��A;+L�Z�F��1H�P�ƀ��� i��l�RB�v�TaM����&��緑jLJ%�Qr +-�aCR����լ�ˏ���U�4�C�x��� ��ї�QX��A�h�B�� +��U����ق��+�w:p�V CO�>"CԈg�i��Jj��sT�l�������8�60_/ ��,���ZKz�&�=J\p���]]�O�f�����0:��^hu��o��׳(c��~��aL�a�9��(5�K���R��w�*k|Gi�2� d�7,*5������B����>����E?=h�{>^�~��~V�uj���o<�TΈ�����7J�� �?�ϲ��G� ��W;[�g� �6�>�kD�d���U�o�8~�_1�Z�սB˶GYi�TG��I��qbձ#{E���Ov����P���7�}3�~͒ b� -�iC� �ݟ�4�0��DX� � ,d��<'����\g'#� A�#x0 +�/��;�pˌ��m�{�lk�2K�)x� ���p�%�L�s�b�Z�ۜ��e�o�%�\J����[ +��"��&e$�B&�Y��������/~������X�"�p�9�V�#pW�o�R��� 3K���An]]���}�G�8��N��g�o�mf��]�Jfc0��cq��_D��4͉mei.+�&$�O�0������o�����A�%���(�:M��"�$��Dp�����f0��3���V;�wR9�̈#��ܛ�A3Η���:z�Cao�tHw�>�� +�O]��|+�ȽqݱdrNa�`�hXA�X�&����v�v���\ʨT�}����f>��E��G��<�Z�O� ,�uSx�2;����%ٯvZ�./t봐��V� W%��9aM�E\���D��:�)lH4��^0�$#�&=�j�`ehy��ݟD�Mx�B��{]��^�~�z�aKo��l��N����P�8�+,��3JG1�� _Ͱ�5eu�,��N}�<"(4�1����Q�^�sh�h�a����.�Q�H] 3$ϔώ7��������<5Ӟ�h\�iq���Z��8�e��"_�@O�Y�]OrW�̍�)���[}��B��A�E��XO9c��Cޣ���d����@��l��v��B��-�M��ʘ'�� ��/J � �G�TE�W���BE��t���&_�ˮ:��c�j�㦎��Ϊ �[=��L��;�J����V�o�6~�_qX +�dy�C�Ɍ dA��%Z:K\iR�Qv�5��@��$w[�����ww?�x�.K3�1L�OF�ȼ�}�4=&�ى'�r�5� cڀZ�Cʷx�A�1W�^�$5�G\k��`�3jCpɴīU�~�,���$|�5\Rm��� U&�:�1DJ�W�Q���7J�Iֹ5٭��JB�r���d�@F[��"��v��~��B����1��S� c�q���͓�u���n�̓l����!e�V- F&����KF630���uò�!������\���o2�b�Y)_�ѥ�-b9|9W���'���H0"Xfr����ReQq�����/�����L[��&ˍm�ne�o�A8V�y�ul)��X&������v��+��� ��>L���Zv^_#%��<2~�`ס�0�&��M���ǡ��� +**�:�B���zk�g�S"BgM[�{����y�ao���/������n'L�[I� �qU�7S�g��8�&B�����0=o��@�5�ݪ�~໇�ҕ�ݍҋ=�tP��hr-ۢ߼�e��Vbd�kR+ն_l�{H�U�h�*i@B1:�#��t +�|��R<��Ns�O���GKy�����#ى��I�1�u1i��/k>]ʥ<�~�� G�\\�Y.Fp +G�T��N3�����] ������(�����=/&��Xk��r����`�?�nc����J#�R��F�� ��g,��ί�]�\��EL�}�4��0������j��u�%�U����O��������^3���.Ħ�ysVSU����&w~��?�m�x�ə��\�* A�DT����z��q�hEu�-^ʨ>j?�wN���e3 �g�S�4�/s~� +��ci��]G������} ߧ�^�wT] �����S0L�-E����O$3��.ԙ�Ґ�Rs�6�A�}s�����~l�]\;һ�����Ò��Z�o���UMo�6��WL+ʦ��c7��E�E�],���[D)R �x�b�{A�����K}���y��~�� +b5��j��=�d��d��r���*��-�@�ڂ��璿��|�Z��w���ep�%��@�7ik� +��������V9<���(�7jHÕ9��&U r������|�X�M��4ؒ`���g$ �[�+�\�jAh^9�}����Ow��o̖ha� +nZ,*`�m �5oT�Sű��DbE�FF�D}���"�$i��%�C�/֋I;�Mz4 ��j���t������T�����{�Ok��֪�PԮ����ȟz�_I��Ӎ<��ZIc5rG%a����1��Z�-��? ��|ׯ��� ���՚��%�1��k���<�o�5��u�=NF�'�܍&R;gH���ଓ���VfӘ�L��|Ho�'�3�AfA����Xu*x��F�a\�P�QB�ڄ�}��^�=�k[j�7pfL�a{辜�vG�ic��C;�| �O�8 +q/�E!�H�X4��d-�U�Xu��I/Mc�p��^ij,ژh���%2p\��L�ۃ~1�#��.�K�y����5��IG����'�(���(WmꙞ�惘�4�eϋ�-0j� ��:��i�-3p�%�T2���S�|��M���� ��abN��̧^���"Ls�xk��Gzr�0����͐��jZ���g�Re�<�蓕��CZ���瘧�J�I��L79L�o�|l�≀�tZ$�{}���r�܎�ܞ+57}\OǮ{{v����l�Q��U�}*.V%����C!�eo����j�tX?�}P�nZ1��+��$��B(- +j$TE��!!c/}��ٖwU���hU��O��ٙٝ��M�'l��ha�[=e��7É� F�ܰ`ρ��l�"������ z�"�Sᯍb��x_"�C��Lm�4�]���f�X�Ί���HL� +�s�)�@�=\�Zx�i*r1\�m�.�_��Q�}*�UN�9���ϭ���֏U�_L�8Z�g9{�Ǒ����%u�\�ו�&ږ$[GxnlyJ��"c:��,o�mm�c\�"���Uz���5�ӊE/p��Up�~�F�l� �Iiݧ�:��@�d=��rs�U�M��9��.�þ��ۭKQ�tN��� /A껩����x�mT������:���-�����f>c��%��D��U���u�Oo1����I���J�P� +T �T8�&�٬�k[3�M#��^�D +��y�����oJ[P��$ �e4]������sRFHM����%2)�1�n��|���r�_5�� ;R�A�fq�]�֗�܉g�\+_�D��<�%����Gf�uzn�W1�?pb������f��H��^j2>��'�T+�a�qP$��]M�|_ [�O)���ҏ:������K�:I�q2zUM�S�M��a����X���<9��p�2�MC������Ƽ�X�-���� �9���ٽ}TMO�@��Ẃ�P���@D�H!UHh�ǫ�w���Ш�W���>%3o��{��7�H�KF[G��Ww0h�~I��,�<��B&$��`9�<�b�gԈ�6��A��&�p#����,\2Rx����������:��� .m�2�Am$V@`*��#�-�&��� \���R�Wh)8*� T��`Nh5#�Y������n�����V���\��1 ���,L�M�\u��%q�����H��a�!g��/5#�(�Y �&eW�(��Da$����/]�_p>��՞�_��*�jR�1$��!��:���ʵ��I�A� ��"���G�S�u�V�<��r��Q+3„�j~��M��ί�٠D�4M�l�h�L���CV*^� ��\+��.��s�ʓr���g�S�����N���w���=+0N�iG%z�d���S�}/{I&�xt�D_��4F�ôŏ�Mh�N�a`~�^�)�!��q�б�B��9x[~�&�+I���~šmF]����@���E'��O$+�Z��9&����-�i�x�9���ة��}Uҽe���Vmo�6��_q�Vr�f��i2/� +m�4À$�$F�y�g ��iٖ�%C�I��u�**HQ*a1vlI�/*tӏ�$:F0��9�H!��JX������C�bf����`�e�V#����-;8V�����C��#��Gᘄ�_�F 'n��**4�BoB� �fK�5��Kc� ��V +��[+�����R0=�J�pO���w�yv����C��� s� %������ޙ�Ji�U�G�%�JH�o����]��$�j�ui陁�V,&�scyI +������,J6v1�"��spS��qf�R�tftF9� �p�$,��}�<��J�^e�I0�@*j�&Q�+���T f߱�l��� �#��^)��-�iրU��"���Ã4ڱ�%����vl�`Fk�^=��=��H nI�h����Ӎh�i7�=����S?�=��ڼ��z��u��xC8�ȵ���U�cL}���7�G;��#w�]�C��vV2R�KEAq��/�)g��m^����ISt�5]�sE�ap�4nH�Nt;��*���_Z���Tm�PY��~�2E=��1j/��[Ƨ�p����dl�(�3f�J<�+�юr�*��!xc�u����ڦjA�L����U�wt\�C�)�޷:*3�, �y�6m' � �k���>�~Q�,+^�[޾�7�����Qb��V�G��Ƥ헿�H�8��&wc�ƝJQ3e���y�i���P9�2�\ +4��3>�-�|��ӄ�zE�ݔ�?��I�� 1_5�q�� r��1�Z�I� ���}��sn�C!��7w���֑ѳp� +�'?�q��`��?�qұl%�y�*��;i��f�¿@�#�̯����"���lr��^8�v\Z{�O���Z6��Z��.l��y�:�af,��)�4���Ϳ��?i�N:��y��=��j1 ����q7�,�6�6��@)�����ѬE=���݆�w3�T7����i�����bJs�����}x���v.��0r&��u���Ot�a!�>+�c���B����&u�>��M����x��9�7j���ڸ��R��fA�"��7/j���'��rF��>ә#�XƢSp.r��)��t^�}�;��x��G-b��� �[ 8�'�,o�i$�2�ʻN�DVC$ܧ�w�i��u����ԸȡLӼO5�D�C槵������c�8� �C�9m��q*�Rs�v���/� CB"%K�E����D�(�ks�P+��e����.�_�����mO1 ��ߧ�&�>���[ +�[�m���BBi�׋�K���M|�)�PZ�!�������N,9��]� E���.�W���!�}ꍓQ?�>��A�4�"p�3� ns����S랼Z� ]ك/� |��,�3���'���8���p.��0p�%z8��0q�C�4�� L +��j^���/���Rk�zح�DC�d���5p!��+�������"�� +�\0�A��fa +k�9p(�l�%��i[�(1�@rB"���_ۇ�D�IRR���@r^��I"� ��- +a�+[�p 4L0����o0��a�.�d�<؝W+�GYm'���k%_2x|���Rr���Jz "��P�����V��~N�djE&�{�>����.������-�Y�xfG���l�ʑ֊e���-_X2\r�s���G.�yU��|�� 3Q�M.�񎶩{���v��+�.�BOʚH��ZR�Xh ��U1 [r*�H��F�Ҋ8s�(�\�ɸ ���®b)w�(CK�����.�t�#!��(3��,�*�;Z���mbĶ�G�X�]��@�-�%���i#�j\Rl�T�( �m�����j��&pL:�Z��\�&}�5[�qZO�C�W� ����=YX���i�减�!<Ռe�Z�7T�� ^���`�7�''�fi�/{��c��zN���T�k�0�_q�Cڐn#n�l���1 +����9U$MwNF��!5��CՋ���u�Y_��P�4"`N��{^{��(�A/��R���Ax\wJ/�4���:�z�rY��`�a00��'U�~Z�efX b-,�`�.�+L����ak��r�U�.����`�дƀܺG��-!h۸����7(a�q�x?n�W?gWQ*5�J0�A��� kXiV��yrm���]˃̊��N�p�~�)������� s�{iQyX'��湺��gkb\��2�� +������3�A��v���Up+�[�F�7��գD�6�A�}[-w)�t��#��ѣdL�>�p�A����u��i�6�u�(e���J�T��xŞZ\2~���H�����|��V�A��2Z�Sړ�9rW)�St� +(�W���?�=���>~���[�F8��=����56�5��4�8X\�:���ʏ?P���c��{������$����; ��v��\�V��#��z���VMo�6��WL�;n�N�f7M� mjlR���id�IbH�+���P�����Cy�%r��ޛ�P?��@�q.C�H��ٕ���|4;�)f��Y�hTO�%kt����!m�׷�_�((΂���o��h��u-�H5��3�� ���Al��V���L�S^ �?]�х��=�Iy����f��hp�t>��E�%��J���`�ATqQق�c���=�=�W��c�84 ������=I� RR�Á1����AUPU;E"M��‰�É &0F�ΕN0�����Z��0��G�D_R�c�5|�ÝJu�Z�}R6U� l�< ���.BW������V�8i���Q'e��c��満��3�d��n��D8��R�)r�HQ7od���#�/�'<n�։���P h�)���2Ϊ�D��u���v���iZ\�,��'�F�'Ƙ�h;-�V�d +a�<]J��� c�A;id� +���ZQe������}���%5�����@��p��F U��{�T���m�Oo1���)�ĂHh��o�)JU����B��v׊��� T�G�J�����x,O�(H[ŔGa�e#�@q�~0��� C��MDi,�D�_b]�=�fhw>�T� �|dG�d�{&���bG��y[�|�'ڪ(F9|���x��䃥d�r�w�fۈ�x +��R��Z�Kzr[��E�q����������C;�uuw���>��bR+�AE&vYT�`�����7� ����̩Š4a]+^�_�L�L[#\�G:�v���삥9����d0��+Nc뇄Oj`�WB�U 6�:��Z�Q6N�n�l�wQ�ђwӝ}pB��K-n歎م��^ަ��~�tl?���{����߫��X���N���v3�Hy;���4����?3�x��?����o,x7z�UW6N:c�1΍_�W�U[o�J~���$ۈ@��H�iҞ�U��OE���X��XU�۫� ;P)�3|��7W_]�\A������Q�dK�f�.��qc��3�̀"ڂ��!g;�P!>JUj��-D4��@���Em \-�&iOS\N�b,#�C��Lk�Q�B�8z ���j�8+�i~�l��9΁v�=�3�� 0�I]ˤ���H Ž��}��x���λ��9��'Rf�X�ž��O�H�)�i��,�@�Exȉ��?��̃��[b�;+�(�% �yen�����X,~�2��J]� �}�yPN���pF�`�?�5� +f�1�숆��=|���Ui�#a�Nm����>����2}$T�0> N�0V;�e�`W2'��<=uШ�Xk��T�a�&'���_,+,,�T^�t�����Y9�hSϻ����h������c��s�d���F��J�q�z9�K?�ш���r��b8�X��o̤FBs��У�5#% ,��_���j��;�V�p}T�|��2��P��*N�ғ͵܃���w��W1 +�I�qk� �b �t" 㳁F�J3Q��Mȸd�� ׫��*��5\_C�[� +4�����.:P��r>Lv�c��0|s�}�I�ʑ�*�{�4Z��0V4l%K'CC/���/L�h�>�Ʌ�›��"�'�Rs%�e��;����pf|�WCQ���X� �V;c�d�Q�0��l�ܵw�H��W�S.���{���i?�y���.y��&y�~��~�?!U/���ܗ3߽��M k�y�i6����X�\ �g�CR�h1�mE=Fç��9�=�AO1�������xT1�!���鶳tBi�v�1�w�+x��o��{���,�3 �d6�%m�rw3���Ha��5{$������ +=���ͼs���1“�aOY +f:�W�zl��[�t���PƬ\��������A2W��\΂/1C�n���W�hφB!p�c>h���<�B82�����b��]v�zc�� ,�?-�8�8Hg��&���by��>PI�6N�U���*�A(��`M�s<���o��<�M0�k�g�?�p��ve������ک�Q�EP�NB1��+����xT�`$Cģ�)}���6�}�㿛�=�����Lo�Ϩ�+4(*��]�L��r81�s�s�z.�9� [Q�k�42��[�W �w ���=�L�D�mO󨢛 lhk���x���rZ̲ϔr��+�Ux�h��k��� uܟ{��(�:��*�x���ӱ�=-��͢;�SoG[Pq�� +GV�—Ԉ#�T�"�M�*�:��[Y�����1�����CN�$�4��m`����{ ��+j���g{j�W��*MЉ�2�}�Qo1���WL�H� �k��%*jUE����Ϸ�Y5��^�P��^��P�y5��̎?�6�&mS/ +-K������ ��5�� |���l�@����c�j=]�#;�'��/b�+v4�����XP����1��0��6������� �*��7|� i M�����hr�`\�y��x7@��"ach��}���-�3�+&�lUDm���i!�|�5A��PyX8���&<����gw�QQh�b������|����w�~Ӎb'�g��F �J��dT� s��G��"l�!U�h4���˥�. +'-������Lp}]�#�w�[���6���1�_�s�y�,{z=����5��+oQyoO�$�;�HfٹW��d�w�ž�o�_��t�Lzx�y��]B������UMo�F��WL7" In���8uDp���\+r(.��%f�R���=�%�Q(��ov޼�y���g9$+��2�/����~����e��ʤ�T*i lA���=���{��,���0���J�+�5p#��ns|�%���3n��R|�n���]��s���5Y���j6u�Ϛ�fi��Mv�V2F2�R�;a�� � +�A�K<�����_��U�0� a ��ʅ �����.8F�ur,�* �C���)��k��< +�xQ�2���,�y���Y�M�A+a �'��:�۫k�zT�#S��.��p�޿�wǥ����mF�3�&`����Ɂ��Ł���I�6��3�F* |���&�;�0�A$( &`5H2V(9�^����HM��7��/����4�����#��M��!GN1����P2�p'� zO� IVHBs�6�*2�l49�p�y�}v'^L�unW����q7�$�5�/ J]�`��v3�J1�G퐾�ǿn� +���hM#�A��%�:��VkZ�h0=�EB)}�d������&��YsX{|8�� ��$L��pU;Y~3�I�XFQ��{m��p�!��煨#��1]�{�$u�)����ѵ7+�]��RG�����ˡ�����7� �]�c��T��:e���W�=m���^�Fk�)���v��"����g��E�)�� �U�f>�'� +e�a���T]k�0}�������I�i�l�`�cڗє��ױ�- �:%���!Ď��������sΕ|�]'"�)3�[2�Ӓ���k0�.� �9b�" ��c"68��@�(�5b��<�F"�L����,\1#q����^���+fI0 �0GW�.�t�Q����+IF�rR�V �J��k�� Σ��v�u�Oo1�����."A��?�E��ZUHɍ���kű��,5��HZ5���⦅�G7�I�d�f���3�(�Dy���AO����el�'���Y7X4nGW +�bӁݶT��g�/^�'b�i4]��W�&}��Zgq:�+����b��D1y*B�`abv�V"��.2�!lZ�a��E흡� .l"?kq1��<�L�9�w���������F �:ú|d���I)�sl�L����3� a�h�ǟݏ �jsyW0� 5�> �2^�n���E��(��`��a�ӌ���0�Eb��B�x���f��\ ��]{g�a���h?��k좳'D����rr�Z�0>)������F�j���ѡ3��X���f����VEu9ْ�mU����!�R���7�i��߹�%N��/���W��SY��0~���²�!���u��]�t��B�X�<�EeI�����ȉ/Z�m�$�����+�(� �=����C�z���b� ���C�4���1�Ku��ڊ;�N�%C,xG��;{X +2�ɺ�m��9�0��0�k$X�.�q�C�4�B&i ��j��/����K���d����h<�2��J��fN��G�M����n�y� P�1.C#<�ʟ�0�Fq �{[�D�6�,/"#*�NH��RЃ��N$�����{�qw�U{ -i��3 � ��B�:P+T�4Vh���,f3�A�d��#u�p�� �)��j�M�Cu����6����5����������p�°n��:XM�� + 6ᵺH��� �œ��q�2k����k2S֛5>)�>N��^ �C⏄�l�,��?�U���U��Lw��3O;.�6��/��I� ��|$`� rہN�G.����R�\����vN��;��2��;���v�<��eȩ���y�~�RMo�0 ��W�P v���5I�ni�؆�a��,Ӷ0Y(*�1��R7�>}�D���i�ֵ*�Z�II�r��_�)���e��Uj��'����تN3H+�zRMː�ޑAx������ ޔ�����6X +�Jx��  +ܸ֡uc!S���I��-���{K�-B�9L��ZI4A��R'XY3�Qx���}�}\��>o�b�$�[��*������8��6�D��:I�ʌ��;![Ak�-md�e��{�q�{�.#d�eR ���v� _;�I5��>1����0�:�^�?2J�$����n�5�)H�W�Ԫ� ����P���lv^=$�w�L� r$w�%[��b��[�G.����Q1�#�����k�Yh�x��P\���9���.x>�ż�Ai�>S@ȁ 0�k���$��g=5ͯ�F�V�ӓ��ć�$��uP�Ur��Ab8Z2��A�QƗ3P��I�����ُ�%bp_�`gUuF1F'Kxe ����, E=ip�ſ�4�q��.�H��V>h~�~U��n1��~�:p��B"��%�D��O����=��׶�{vY��;�$���O�U]^���“K������+��7��\���[��1&BTˊ2�!�=]̊�R���s=�s&|H6�"V��r��ay_x�>ǖ+m�G������P��DM�=\��q�������8�wJo�e!�<�Y�%��&�B�G:�s�6�w_�w�j.��*V�&�Ei7_���;��u +��6Y��MM�9>�2�R����uRt��f��T]�����n�I'�mZ���<[qQr���-��}M�Ew��xU�ﯰ/��c���kO���~�~2�RM�A�ϯx�$,����kĀ���M����LkOWS]���.��$�!��W��R�а �<ɦ��w�'�/�M�|Va�/��h}`��Dj����m�����W�� 7�k��7��OV�X�F����ۆ_���k��)�=�X���]�K +<A���h���D��;QX�h��N�#:x�13|lE{2/�)0e����}X߯>=�F��:2�(����� v�:�>ˠ��9F�W�zΉ�#]˷2�EU�h��X��7Z �W�٬��a���-���QD�h$�Z�g�A#Z +�B�Ϡ�L;t�@Q����1/g���!����$O��Q��Eu��A!�a���ך[Q.���XAv�R�0�3&����4�C���#�$ +����~��_����:O*?���_ƈy(�~^>8R8�����kf=-���Ep\��^m��rv�ӑp�ڸ����ڊo����TMo�0 ��W�P�v���5�ni�X�ݰ���ZI ����^HN���E2�G�=�x�j� 2Zd�߾)���i��1 Kc CP$��pט53HS�d�F��%�'���*��$ �^.��� +'�Džb1��Gl���������b �*�� �E+�xW��H��l��W���ht�`���J��n��b���M�}�M�?�_�T��4J`�*�]-�`c���ٷ������3�V�Ai��F��ϓ"�,k�7���[\�k���L[� w�����������,�����2RDg��jY:]�(G��޾bF(-9X*���45��&��#��w����[�ƴ:��yƱ�:�� ��a��s訶��U{���qK�u\������N,�Jop�8ܔ#X{S��6Z��GCA�-���a�b'�!:�2�N�I�+s6!TUD�����_}�(���U4t��^�c�z���mSMo�0 ��W��!v���5i�n�� +l]�t��,ӱPEH:Y0��Rb'٪�L��=җW� P���0g!��U�y���f� �����X� ����q)�Ƈ-�e#����C�j�{C�KE���{\�| ,�Q�a����C��1��@{'d�V<��'��n��w���ht�`\�i��x7�`Q1���&�?��=.�b�$L%�Q ��]/�`c���ٷ���:��S+�4�S����$G�Y�r��t� �b����02N�]t��7[\��������V1�/F��?̒�6�߂�b8���.�C�^+�k^\h%2�/��Z ™��i� ��5����U{�B���PaAG�,.��Gn�=�x΢����Yߴ{���drܯ/�j�r�?�i8��kϋ ��ۣ��Ғ�O*���:���D�zn�5����ᖝ_���*�?m���o�bko�c[VȬ��n!��a���O9eW�j� 7X����ַ�QN@<�!����Vi�����T{�����ϵw��Uޑ%ۊ�q&�7�Qڬ��<�<�+^$��1 ƥ�omLO�)����]���h��`Z̏��S}���TMo�H ��W0EPKAlc�u��6M��EѴ�H�#J":���c��^�lىӏ�b�����ș�?c�D� c.�d�V7e�G1˦g���*r$ +� +>6��I=�*� S�(䶀��#�v�EV� �/���I��s���%��v�p!C�26Ct��`| 6xeZvXv�o�6U��={B;���|�5J��CthaE����~u���:����(��@I���֤ hj^B���rhy�yӢDc>6�߇�zGfY��>���lD����Y�YgD�]h1�����C5�J���E������� .W�a(�T��ȴ2�p�6v3˞ g�S�CB얎,T��=��� ^�;��U��pj��b�(}N�A�Ŗ�h��QS�o��j�M^���|Sߓ�֍��q�A�Q�O�p����c����o��`�{��Q;�Qۉ���%���_3� ӣ�'TTA~�ț��IT��}dU� �������z�&��qn�c /j�+����am��h�Ҁ��A^�`BP���c_D9ɏT3�2M�F� +^�k^���u^�/�(���4� �iL�`���bT��|�����I�E��;���=��0��,��\�-���5������S�ѧ�]$���8 lj�>C�����. �n��G&�_/�a!W�ʧ���X���|����_̲?�E���A��;���n�0��z�9�` N�^k�uk$����$�AS+�-M˕ �Ȼ�%��ϡ(o~��]Mޅ:�$m� +-K���o�q6*2�R���X�����}m�t��%�>�٬k�@�xώ��*��X"&��V��UI�!h���pG 1&�f�䃥B��;a�j�s�o=CjB�X }LO�5�\$Wy�(1� ,�H�ڵ�>.�7�n�U;��J�S���,*�3RC���7� ڗ�ȣ̩ Š4�V����F�Y����̚��[����3f[���b���V �:��szn��…F~�MR��AlV�hT��)˥�. +7Z}^0<�<��]�t.�ؗӎ��/�N��)���J�|������Iv?����]���}MrD�  Ŭ�';����������/��{��Ot9]�̽��z��ÿx�-���=����l�gk=1}������SKo�0 ��Wp@P��#ݵn�tm� X��N](2 S$���k���Į��k��t�E�{�����(!C�a옔� �Jt��I��t�k��J#(� ��M�x�&�Җ+R��!� \�Ax������N��� Gp�S�X �B�s�\ ˢD[j� L�&5�ؒ� ǖ� ����#���J�q��悕5GPja�p�����r��v�6Ƹ K� Sn˅,�޼�Ii��r/2b�����~߼HE���� ��j�+�H�nH��pER ��Z�h#�i�$¯����p!����dK+/�'���:��>����T+ْM&��TI����ڤ&�����^?O��U�c����3XX����P3���}�ԟ� +Y@��z<�!?�uq�Ag�\�r�Q9�m�x0�\]�q�Y���(�̻{�;(�!_���J�'�N�:j��PԦ�q ��N��rAv �m��x�>�)q��ԧ�.aM��v��. �"�b��ס޳]�!sH�K�m'7�Yc��Z����������X3�t�� _~��8�T� ��!ex�N�*υv�*�0��� ��z�]��x[0�VC���W{\�3]Y�Ї���X�G ��ܳ�E���gv-Dj�Ҽ��ÿX��9��˯�ߥV�n7}�W�9�5�}�,Չk�AZװ��%�AqG��)r��J�{A��b�M� H�\Ϝ��ٯi�B�\2�Y#�}��i�K8����A�A��X�k�M�?��K\�toD�Xx�B�$�zBc ΘQx�*��p1�%�Y�\c�Ψ<8O�u*� Sp����jC��+m�&�LJ��w'-GEB���0+��@*��V��������fy�L��l�,�A$(���M���Ig�#p�)��� ��#�&�|��<"��(#���3Pj���?-����,n���h�%#�׿青�Eh�����η��RĊ���W4b-и �DjĖY�1u%f�����e�%����3���]u���}O7m\v��M/�@e{jIuU(��J +^��ȵ"k2n/�> � �꾏U�Z� K�Z��@+e/5s��#�t�s ��Bu�:8�^y:J�x�y�.���b�.�;z����ùM���d�bBbt��c�j����L��Qҕ9�yT� �Y�jc1�ü��&���Z4�v��vr)�ٕf�iPjN1�#�0,��B�h|��T&e�V����0���j�1`��f�j��4���W+��F�832<ώ�T�K:�3H�v�c���R�M5�Q��ҝ.-3Α�O �ץ�q|!�>5ܧ�$�Q. VW���:�S����� !FG��t�hi�PqQ�2����:r �S��HG�'��L�7�����Ѻ��N��'�}�V&�3�\V0�.�?�o����)r��=�h�6�KP���3$+T�>�a|���@"�8�r9�m�/w$��1�J���󟺦;�^�����|KO���0~r�9f�S �J�:e��u��9�q�������X򏌔��L)KS��!���J�o2)?�8�4^]����oX��g��e�C�dc����iA eQYO�V���>��u�ZT�ŎQ�]�l�ug�²��kp¼���3��V��Q`�Mһ�ӫy�h/]�V�؟Yo�z�Q�J׬�e1#܋&�k��W�Ï���N�ؑ?�y5��2Z�Pz:�2�b^9Ó������j�?���V[k#7~��8g3c��}X +q���:l mR�K�Țc��, Gg옒�^4����m�����w>��$N B�a�����t�?����d�+VVJ#(� ��/����2�;��I�c�@��+�ߴ0/H��J���e�}���p)+a�3�Hp�ʅ�$N�&�!���I-S�䊄���c�U�5�*���J�qʬ,m+k��ha�p��=>���x��PYc ��p)���v�c`߼�)Ii��勑t��_bA�9Cd6���e�� K��[���2�ب��Q�c�Rȸ�`�}g�!/���"&�H�����U�Z�x�4>�����"�li�U����ć|��%��&�b�=���������9�2�D�~���C � �1�λ2.%�� G��=*��YiSe�.��O����d��(�aawg#/�}Q�w�P�Uݛ�R1t�Q�P#��k�[=ȭ7\���Q�p�iWr�<�����={�bt����S;�@9��w\�_��g��G�g!����)��������"´��{-t�9 ���WU��ap�do����k�0���W�C�vHm���Y֮e���uc/s�ϱ�"��9Y�ߋ��k�ل^�����O�w� P��ȔEa���C�x�&��r�`�Z�1��D������P�w\�p`�i2��{vW�/b�0Gv�\��i�Q :�H1�� ,C�K��ՠ�6�N<�S�g�����������"�q��-��n +�F���}?�iu}���&Y�`Ң�#�&�����$�G߱&о�K�pK1�&�k�W�g�#3����r:%��Ն�J�$Δ�cSG�[[��fV), +wZ��a�O�%��ũ��|S�a�}C�ø��� �, c��<&�؁��hg�r��ņ�K'��,���Ȭ�>��Vp^��j�2��W(��6X:���!}w�7�+�1}i��HO+=�G}PMo1��x�( �J5RTEJ�^*!�eG5�5�����^�*T������ɇ�F�d�*� +[]�.R�W��Ѱ�_[Nh�8!Q�/-o�����Nx�*J[�x�'g�OM��4[�滚�7x��I���3u$��0�m�e"��a�W�e�AR����9ط��vl�'�&��(���$†i{�=?=̿�γա��F�5 5�c�ز��\>�N,���TyTx���%��F�Ï���:���I�s$�� ����C�6F.9��j�]�Τ(�1J4G|\�n�آ��ͰX���Jg��jw�W}x~�\�v�op����Q+ҋ�r�7,���+�w��_6;K��9�I�Rh�}��������������i�������J�7���W���ɾ��QMk1�ﯘC�Ǝ�v\�iB%���T0���+*K�IkcJ�{����R�N�{3o捦|�H�T��Z�e�{ +w�I1�[�jm:� �p5^���q������(e��l ���?�c�T�����*� ���Q �/�c���7��7��VA:Y���8t���B�yPOh�%�@жv�Q;;�7$a�i�y_���iT^,6"b'��Ha�c����eI�N�+� +6����F�����4"�\\o�$�*`<`��[��NJ�4)5=뭈��������qB_�ԡ�}�2Z�n�L`��Άȭ�噁���R�dh���M�d4�i�Nm_��3��f����b���n�J���E��H�+$�|��g�'u����hֈ�`eO���ņ�j���w⠝-��t�t�b��2�L���Ǡ� �% ��gn�>�N���+~�U�n�8��+��SK��`�u�5���lP7�K���FQ�$f(��&���,�r��e/ˋ(�ͼy3C���+�(� Lٓ����p��e��l������PA18Al����i5bn�R��C*3�@���g8d�r����8������ + ι]�t�C�4 ���ƓZV�7��[_"�� #{@k%�0�2����ʚ18��6 +��ݟ��W7����K�a+r�;.�a�| >�g[�D�6o%�%F�������O����4I*q��)�i���ϵ������#����έaOB?M�3|�Z�5Jo �I�F#�����aXv�6�# lCՂ�/�z�dMX��i�i����%�m�x�]� l�F�u�i�3���PH0Pq>���`nu� ^�[�=�Wl�/��Kk5 � !�V+�y����E�%�y���P,���~�Zx�X�:���EmҔ4�� +YB���(�[��H��\a��7}哙�k�r��V蛬�Y��1�p���pz����ʋ�Nx|��<���kBᑾ�´�?�NYt�8�?=�?H۝�^�^�`�\�4Lf[R� +2ʬңa4W�ˀ0�' '�Nx8~x����4��N�� OA��������-��d�����~cA�����J�v�rx���[�O)x�VF������-�n�ፅ��k���=�o�V���h?��c��� +����^�~�ڂ������2+h;����Å'�f8�>b���6ׇ)ʦ��&��Vs��>%�}��n�0 ��z +Z�.���Y֮h�� �m@��tDD��N }�A���;TI�����h#�h�NX�$2�*����SY��k��b��!�@ Q'�����ot!���@aJ�O��~�I&:y�[�75NG���f!��;��`���]�Ct�A�L�h�JH��B�M��=g;2��|�F ?��P3–p��=�,�TgL��i�����v$$���&�`B}�|��� Gm�V�Y��M�R��ܗ7� yi�����#�>D��'r�س�;f�J)�43�����2=�v������? + � h��3��2\D����kd!ߍ�� �@u/��E��x�B��Jl�(��]"��oBqJ˫7\\=�_�_�%����:�j^H"�*�р{�R�D�J���܆�^5�����k�Zl��4,P?��9�M�f�а�p �3$�:�U�K#�̅%��8p��~��� w�����[�4��Ԛ���_S�ȯI��Vg(hr�[Ѕfw.��*����t�Oȗ�a�ƭ�������3tuBVp�`�r�u=���/M��N��`��IƟ*դvA�*�O�K�ٕ�w�X��1�Z�z��/�J$��|�GO���Ol�$�^��f�|��ͱ������cj&�-$��Tb�V����QS�p�*��:���~H5K{x�ޢ?�Vmo�6��_q(��SI�3*��(�7���m��ָ!�0��g�Q��nnd!Q��"��(���P�;� +L���e ��n�KF�k�s�*b��)��F�1|q�_�W��ַ֔K��� ѐ1��� ^�)��䵨E�"kS��8�PKB>D݋/�"�QTk��3h�7��;��w���^������@���_>��oW�k������ޏ�'?*$�cA�o��kM�Gqr-����_ɿB���d����Dk��ڐ�\��1��-�8;��QM��Y�+�s��\X�TlG �Bz�e4�� ��X+��=����~�R^0j���Ɇ���$1l�Jf�sx:�� �zS2z辧'�[S;����a���ktE�З�� 4&S��*�>�r��7�] ;���6n������c� �Ć.��b:�ݏ)�|����b�jр_�������u-�P�l���j6)<�����dσ���jø�<7B���eF �͓���`Y��n8�M���-����IP��<��7��g���m�{4Y����r�D����I���r��;B����P��9N���K��?���6c�mL�-q�x芓�6���d��l���71Lp�� ���9۶vqO�.�/흍3*I.�O�� Nky:�n��mBܢ�܏�kܙ錓9/! �-5#��~?��I�2�����Y?���$�9����7a������o�!�� ��(r�z�LOͱX�'����&o��]�Z���iR�'p} ?���6�}t�[ڿ��7�|�ߤ3��~m��Qw�59F'����M�5э������I����W��w�F��VQo�6~ׯ�.,���1��d��xh#Zua��):L&5��c ��)ʖd)m��E��ǻ���;^�ϒ "�)Sj�����e�ǿ.���Nᯄ4Ĕ"���)2�YB�w2�)zN �|�J ��2�7*��)�7�����b�p�9*�ҥ�&K2�Y�LD��0�V��J{�H&A��4��n�)q�D,՚�bY�L#l�n߇���a>��\`&a�LCD���l�$`l�Z�#p�!���Qg�#���r�2r��H� ��gˏ�>>-?M���LJ˦r�Э|�|���']�8�����0 ���X��E5Դ�RaC�3E�ą�G�� �Q��,�&��'�''�k,���?�z �2��Ki1Yޥ{�MS��.�b�R����cf�h���e�i wr�1C+J���6�� �OO�f��mխ8S�a�'=�:��p�%Q����9-�]�U΍T#���UJ�P��r =GOj�i~> �z�D�]0�h�F�O��^�V���\�6������2����_���:a�<���.�&W����������Q��~��t�7h ^���T��T�x�~��V��4��A�d��d� K�����vS5$�a���-7�Ŋ��v�q͖��-ܹ�Hԃ�.�v�K����A����e���_�3��� =|i�Ώ���NAԇ�q߬iM��w{��3��]s��RBV(�Z(Ź�� �e� ;�v�g��2\x���7�*7V@r���V +�Lύ"��FW*ډ�����L"G��x[˖�]����u1\���-�ߓCb���퉺J5�'�,M1��q��@��rv���j�-y�t�z�v��'�G�s���¥�I��E&�Slo�>O������Hgge�r��i�'�����ן��BN�(Oi�ZV�\Q�~�&��0��K(�8�R^� +<���8A������S)Hu�/��e����k�-ݬ��8�� Z� �,�QMס+�TeE�2�P6�vV<�kq>����6�U=� k����p~����2��aڶs���?��� &�lU@�a�E9�,%$�����]�E�L��P��&<��߻e��I���tdž�Ah�^�Ȥ�oG�s�˟�T�L�D~��5�,�7� ��q�(�[۰wvCV��ث<7J�t�M�㱝ƻ �I��zmX������j�� �k-i_��3��T��o<�q��7&�@w����.>_N{�qY�v�y��eWh�=;\ =a�me5��ls� ���8�ώSXڢ�M_3��>����J�!�>Gg�Co��r��f�D�˹�m= =*o��0�Py�R����� r2$����>����3b�p��ǃN�ώ��Ir��$��'c��v�i�}—�?�TMo�@��W�!�P����(i#�*�F�R4������;EU�{��ҠD�!>�����7�=}��LQ�FouI���'Y��A��V`n��� +aץ������<��E��19��|p���)���l��+hpS���E��"�S������T� 0�+�Y���%� Z�+��l�S����X?�D��Bt�BP[�[����/�L/��`Z�� +V.*��j �/�bC`B�9r?�$�h�K��}��I��"0��2��W[��*��bv-ɫ��� ���°F� ��H����T_����$"G�5*�����dM��9k`^y�<��[�(WF;��np�VLz� G�6g;d)}���~�����M�kk�yɏ���!��!r�AF�)���AR�w4��؀v�駪� �fV#gQ�=����z�2�����8`A���-Kޚ��]X-�Yτ� 2�P~\�>V�?�w���_�w���1�}������Z�c�ܳ�mNh�^+����ߛ�X^?�v�F��j�L���۶ mW��?s<��V���e�t��m��n�0E�����B +�@���� b4@Pq��19��2$;3�c��Br�U�����ŗ�xv��k5 �~ٱ�~��̫�� +���E"#( +�!�x�žo*���\�v��v V�_#��,�X�$��N���6�%�@ ߸g�B�����%� %��I���E? +�Y`��c�;��'e��fy% 9]�D&e�F��������5�YG�)|�S{�u�^s/�Ჟ�o�D����#y�?��W������(������i�1!���f��b�Ur�Q������>��Ʈ7�_�O�j�擙eò�q��M3�>�5���zI�O��b �^����,˱n�iX�@z�6��VH8�l6��\{��W��?m�Mo1���+�D�P�@iH�HQA���Y���blwf����j�So���;�o�)��" Fj���c�~�2�V��]��&(mB��b�7�ք=�*ꉧ\����ȍi! �9�CLiƒ�P����֨Y-p��h!4���4�Dt q��r2 ukY���Bր6m��.��CRPH�,;��� �V�>��セ<=�X?w���5lt`%��O�` YW^s+�*�W�w���ְ��_�E�U�"�� +�lXQ[As܇�]��a{$|�WZ�j��?�ߊ���u �6mr]�\k��|}Z��!��@Wzz�'����U���&�As!�d������yt�]�v��-�Y��h�O��q\��zA�g�g�Y�=P�NA��W�!!�؄���EsDB��ZO�af�ӻ��ߣ�1�~ԣ��W5Vt �+g�T��ڮ�]^������QzI�4T����1��3�=�ԝ�&fa���m���j K����c���)V\�f�3~p�bَ��+KM���C(�Tփm�ߋ�"�)!|�O�$������ޤ�S�D߈Q���~>���Z�OR�`�a�:i/v؊E���AJw�|�g�>���Cy�d�d���≭�Q�feꍛ�:��:I@?�0��a��'�،ݤx SW�Q���W�E������R�n�0��+�"���5�]�A�(���@AS��(M�˕�Ϳ�%�yݓH�汣�O� �H[ŔGa������b��� %�5&�6�`"�b���И �g��>��<6�\�bG�l��I,���W�������RQ�r����q���&���U�� �U+�c/��3�!ԭ�����F���j�k%ƻ3K*6���w_�o�7�� &�lUDe�^�*l�4�>��5A�j�<ΜZS J�w�{��I��1�r:)#6N�I��UVZ���W�qA�Z�BUbYP�vC ����$�}�� �e��F1\k���布6%�GO2��w��}d�䞞$�����o��C�����,Qc�8��{�C�ת=��j"9:Xv,(�h���0.˽�si�o��:›'M!)��=x!��=޽��G�M����Ӯ����3G�7��G�O�}k+8/�bp0��۫>�ӳW�F�G��������h��RظǼ(���D�E&i�W7� U��>�����Q]O�@|���J��#��R(�T!���J�r�ħw��:!���Ȏ +��{9�wf��ǟˢDN��T���{]�$'�Qr�O���� ����4��s�nI� �<�kv�B�� g_� ?�Upl8��{sbJ3#�L�U�8���iY�KO5&�1(�Y����� -��{حz���R� ��F] �(=!,�޷���E�� ��Q�� w�Ѣ+��/�bK�1�"%�<���n ���G��(I�7"�꘬ޱ��D�$=*�\p6ecuB�*���oQ�8��q�4�+���; +Zk֣���(�WlG��#57�o��D��yآ�}��;�yl����tG}G.kM֧W�3� q��=%o*��[�Wz���>aڔ?�2����u7G�a�0F�اٮ��0išs����GM_ɍ���t�b_�'x�� m�^h=&�|S��j�L��۲Q��e �Nn�^�*���B�g�B�w\�[�u�[R#>�*��H3 q04bv#�[L��b��� [�fi�y#�_)�x1��=%ϭ�Qo�0���)�U�j[�i]���`M�O�&׹6�6w���wGN�Ҵ{?5�����ݹ'oB�@ma�BF˽<���l�����4 3c CP$�gpS�%PG���Hf^ +�:�3ro�r?���D�����������T���VHp���P��b � +�� �i%����R"�*kAo�c�5#7����xw��b���e}�������ELU�R ,Ca����FJ�h�}EA�bm9O�z@J#ܔ�����"�$�8r9�W��G�]d��vw���Q�h�����g�(�E�v��t�ٔ���[�U! �a�;ȇC8](�Kc�_:�U���q �P�Лu�GIsZM�����w,TiIw��$�Z��z�z��n��5c����ԸJ;V�G۟�1��-���و��- +3��E���T\�6Ͷ��"��ܚ]��W���6WZ��n��hoGk��jN� 7O�Q�!l���9`�2��0S���!J�2����ʶ�԰l��D���[w����b�1Խ��;��$����elj�������U��Ե��@-�a�~�� ���^E��.� ٴ�}�� |����H��\�/^�.�}��_]�9'����V�'�6 +ۓR��8bϽ��I��N#�����~�R]+1�#{�N�Jk�z~Ͻt�f��YO��RKo1���*尋��B($J�HQA��"�X�������*�����C}�g�{����FI��\���g��$W_�A��d��r���'� +���[Q/C�q� �e��m� µ7�� +�����{���%f47�����C�?�몦X{J�0���A���,;�a�x{`O��Y +Bpa�Ũ���'#���u;wws�0�MP�1��bm��-�X;��ɼĆ-��ro���BRKx� �şm"�,�wZ�S��W$0�;#����Gk<��(N#o@�$I��ވ�>�L���A�J�L�l�N�wC�T&��?�;�W���-��MBOŚ��(�w�A�}o��Y,�`Stx~�1�rc5?�9 ;�t.R\�Ѿ��S����1 o��gv��ɵ��Y���1�#�[ �t>�UF����Td:L�p��U�<Ы���������ήh�]�QT�.�b���<莖�Sj?�\o�ܿ���� ���_v��j��o�[��VQo�6~ׯ�"qܾڱ�,M� A$ P`�:[Di�;��]��@J�%�h1`_,Q��}���苟\� G�aꙔ��:���$ ��ByX(��<8A v�Z�yqmݖԲ`HeWd~��|Eb� ^Λ��gg��s�Y �b��ٸt�C�4 ����I�K��뀷�� �E�5�]��J���,,�+k��ia�p���o>=�WQ�a#<��W�0���8���$� m�H%F��;! +Aw����I����#z���AZ lA�V�Ο�se��Y������y�-���{lkg��hrWs�$$?�_%z�<�w�o �h0�˵ 0��?E �>��"��Z F8���Iҵk��*��V�H�:n�m��G�1��Ѣ�6v�\+ ���P6xy��x�Rrz�K����?�3�I��pV�5�������=�ߎ+��"i�LpB��l\'�q� +{�j黮�pV�"����"�LÝi� _9��k�i�ŝ�1u�OwK�VҬ�sk�bԧ�Dn�N�������nZ���~N�џI�5���7��e�&�y��b N�K�ߨ�&I}�:<,� ��t��(��Χ��%b��O�a�oޚ��Es�_[�h8Ͳ�^�w���1!-�/B���G6��Ռ�װ��t���*���!�8��S������~_oI�Q���m�Ak[1���s��6�&��m���J0v��"����(���Ϯ)��E�vi��ݝ�F���+: +� MԄ�}�c%}{=]���a�ϑ='+�C鱎���è�/�(�-&a�;Ʉ��S��d��]�yGﮰ��Wc��H VzY��X��DM�;��Mx7X=~,��~H �OzS'����/��K�BM䕰g:��OO��ۇ��Y�Wt��,�p`��V^� �Jw��pٿ�V���|d��b6>qCZҞB�҆\?�m`�ec���:����o�����g���:��C��t�����{�ޜ�6T��9.�iJ�L?l���9EOo�/�-�/��T�N�@��+搃Q�(4@A�*�R�Y��i7���q����+�8"͒�P���������K9j�� LZ���.?e�d�O�/%(� P�X��T��h#��L�R �ܰE�b���,.[��u�g9^��3�TR�B���׾�����栝�Y%��[�{� %BQzӽf�h���B 9{ޠ +K�Usn�8���|WK5��T+ ����V$%H>��5�vyy�X����Fx*?��D�I�� +&��� ��� g���J��5�I�>\/C� JzE���f�4��u(�N��A�Ғv +ݑ�E����Wo�|�[�_��s�6׍!��s3�0� �dp�T� ���s�H�s�([���� �Imq���Jzz5džz�V�4�4��C鿳�8����{0�c��FL=���!��f}��Vf{0�9�q?��C����_ai� ']��۞�Ɉ���}%)��μ"�Q^�rGx0*��_�X�rG�͇����Q����U��D-���f��j�.����Ӭ�Z_�.�8& ���5� �R]o�0}ϯ8�� +���|� 1��TU��I�qnk���oh��� +�C�d'��c�߇2 'mS7 +-�e(N��Fٰ������(�%���X� <���� b�Þ�S)��>�#|��� ���bG�u{��iz��U�>SE�ql?�B�K �rh�ͺ��`��3�$���G���F��� +�%ƻK*jCۆ��~�xX-�TLJ%ت��Ŀ^�ck�����W� ��m�a�ԆbP��X*��ߚFFY���K�YQ���%Eok�qm4�W�~�Z1\e�d���M���) Geo�[uNQ��@�H,�JB�ȃi�t�Wkk4���T(T�����>�zw�����2�g&�ɤ��;�uz�Q��%�W�M��4�<�N�/Ӟj_��;�a�� @��$�ɱw�U�|4�y����d���-�/v�B��{=W֞��Tx&Ўt%�=��^�.��$���L�l�Ҵ} +����ݢ�r��P�Ζ�,�t���S����`6��Y�?譒��h}����b�a�j|�GMg�K��-#�$ւ:ζ����"2�R���d�Om�s)����ɻN:,�&_J�����s�ٜS\�!M�*�hO��%ب�?_�E� ��z-�}a5i�o�բ7�X�����m���Q +0����1܅�E�� m�j�� +⃦�t�1J/�e��Eʭ�b&��)na��g<��R�5]0wGV��x4���=&0� G�$ ��t���H e�{I͙,����pF<��*�K&$��M����#�z��K0��.�V~eVy���)�S<�(�*_���5� ��G��b +S�L)MU ›���pR�y�ض�����z�#a����P=e ���-���C[���X�r��jd��َK�Ss+�z�NU��_�l�����;�͘�!�C��3�Ú� ?��r� �{�09z��� r/m]�RKT.��UP&�nl7��[�a����r�EZ��=�+�!7)#܇W.��v�Pf��۲e-� ���L����i����0zε"T���@f�q�e �!�޳yG��ݹ��zʜCKp��Sh�-mg���LJ�a�E�=��ԟy?F��A�[\3�A1Tߵ�V$`/q?�����&�a@z��s��Wh��<-�Y�X�A���M�<�?�,:��ղ|��!Ԍ�a�l�3��R�Q��2�ci�g^���������F���^�= +2�jA<�� ���ɼ:]/�~�f<��D��ƶ�S8z��C�"��L��ѿ�TQO�@ ~ϯ0Zӊ����Rc�!� ��^���9q��l_K5���%�d@��Sr��ϟ�9�ˢ� �U�) -#Y����v/��$Ё�aȍE0 �"��eaf��@�8��̤Hu��!|��� Á"�G��� w`�c�b��O���.�ʢD_Z�@P.흐��K�SO B��b�hk4:F0.�4Ub�ہҢb���y����d�u8��*aR(��b� �\���Hų���$�%NM�K�. E����H/IǾ��̠��bt����U�s7S�d�4 St2��XFx]�;s���j@�i(d܄{I��b�3��$�])������cE�����N�f��֢�x[��)A؞5�>*Q�����5�Q�h��c��%� mgJT{I�v���J�Lk@�Y� !��R5��e� ʩq�������FԠ'�@n��V��ߺ�Hf������E${o�Ӥky8L���kx�oߵa�ߏ)犛p�F�<���G�~��k��� ����6�����'>� s%�[���X�n���.KW��"nr� 3o�F&�t��z�+�;��pw/ �h���G +�sp8_��i�΅�#��R���q@�+� ��[ ��/�p���T�o�0�_q��� Z���26DY�nBe��6Uƹ$V�m�(���';����������ᳯ>�LC���X1B�:��w���Y �G�O�VU��E.8$��^��#WҒ)8�%�C�{��DG�:���a��:r]�;�ؕ��6#��mĔu]Qf���9�D�qsXUj�������;"S�,�Z�bꀭ��3�m��$�Z����FH�����"��v2�֟�jʜ�Z5#¥�v�p�eG"��^"��]��|(��v��0� =�Xje��|g����p��)RKm�NYp�kǭ �� �����2H���E����1R]��^���%[��xa3^��C-~&A���� ;���ZRsƆBRT��*��N��} �{���)�ovtY�?�ΰ�a71�Nχ��ykL��?���w���:�!a�ų={����\��� ���wT?-��/=P�jA |߯��<��$�v�4!��RB]�T(�=ݭ�Z�H:S���.�>j4����c� ��.͕���s#{�ڄ���+|�l��Т:j���G�������L+|R!ܗ(��n�F��/�uG���>�s|��[[����Vh""J�Tŕ��W��OU�Џ� �w�؅�X����\e�V(��t������EM��2�NV��;K��=_'g�+ܷң�� =�p ��s+��4Ad\�s�edU�wN�+���c�s�4]n��Ӛ. +��Fx�B�#��p�'�Ҷ��U��Fe4;���8?&��8pKhz�P=gl%+Ҟ uc\'X]�*��$iu�\]��]�P�1nc+ &������F(O���,E2$�cG�;(�+\Z�D� 1�|�V4����F�����C���gc�c�őP(�9�c�ᜄɾ�DT�]�f�_ �>9Zket#]�K?�#��#��pRS#z�(������ +ݑ�dc�r�.>�"�;���tV�6�d����m�tP8�Av��I6�/n��B��Z���QQ̚��D��l�!�M�23y��Z��j���bH�/�N2����^d��9N���R|y���ߐ3'�,yL�E9���G�>�������g�Q�ؑ�&�r�l�'Sbe�&�ض��~�^��9B�/�.-�M(��ߊ���kq�X�H�e���w������yj���d���V�n�F}�WL #�V��7�R|�� +m,Cv��V�P\x���]���^�&Q�I +To��9�hw���t�!�@0B�X�ەF�>������17q�� hFT�1�cÁ q���4��u�&�p#�|F�.I���ύ;><��˙��0A�KS�t�Qi�)� !P��$V�)~P6F�! XwOт( ����\I�@f�Y�?����C7-� �1��`Bn�^‚�l*ި��@���#� �f�}̨�F�#�[�[���-����������z�#Q"��!D �w�\�[�5�tL� p0!&,x�1=9g���4Mf(mw�NsZ�f �*i��~bub�ϴ�h��|ut2<(�~�n��qw0�� g��/׃��ݟІ��zw���z�r2X���j�����Y*�9��s��2ܮ� EtqQ-�[a���+��K{OjJh�'2��H,���3���M�l��y���w��4=5�w ��e���Ro�Ճ�1�i��a��)��HewYN�4��6���+TL�.����_�SaO�0��_�H�R4i�Z�`�mH�����*׹4��NB���$�aB��)w~��;��S��H�Kf(���f�)'�&�� �7��H�$����*+�S�?��B��(�g��gqȌ��y�:���:��QA��I�YN:��`*��1/�6�n�E���R���=Z +N��J�Y2'�"��,a%���.Χg��g��2�2�P2�D�M/JP +��y�V��N��bK�9ㄫ��s}WM�n*�$ +�)�c�'��$�K�ln�r�$�d�b��Ւn�\�ȋ��O�:L\��~9�:9==���'A�: p�b����V�F��#�f�2���F�1n�kx��U=�UbL�]�ah��Z��v������x�wn�$?u��]Fc��H^{�������mN{�P�0�5�����C����Kv��Pg�t� 1�!�c�B%����ٝEEɵ,��H\�Uo�ZV�pCM��*%�;������vhw^ +����;��q����% +찷��~m +�}�#���~���w5���\aTS��������P(W�!��5���~���n +��5�i�d�a�~F�m����\�aI�����o&����Ak1���+ޡ�8��^c�Ik\jHZC����] �%13�M(��e7��>������⦄��|tBgj����[!��y6���+��1���H`Eqb� 6��tYat,syn�����M�{t�� '�n������x��Sc��:,�(ܖP(�H�.��9��,zX�# ,�.F�i����))�S�e�s�@�䔰g�G�n�\�zX Qc1 ��;E����j�l6��܉'�\+_U��H��Mp����E����U��H���wg�3���t��M���/��F��j��S�OF�vO����5������:5y"��'�ON�v����d~%�e�i�Nf7�[!� /��{'/u�Ӕ�;�����Ak1���+�ЃLB���&165��ԥ�@�j�Z���x�m�)��e7v ����6b�͌�J(h�''4R���������񬺺�p�o!*ژQQ���6�'��08\���0�c�H&�&���b�$�u}֗ }�`G�S�.�3u$���⺄B\�F���s6�ug,z +\����R�M��)z�J��eyt9OP9%��V��o���{���-�P�*���OM��_���N1���)F�(́�˒@Q��H ��T��d-��5�e� +�^9�@��Tߍ矙�-����A�R ��3)�c�;��n=�ڍp�+S��'��N�:W؊`�Z7'5�bY�Od>ka��é ��u��pЄ��J��%���ƹ�Z�1A� �5LjR�%���p�0-����ZI4A���B��� N�� +�Eݷ�������ja�s�P ���Y�A�8�-I"H��-�## +�NH��\Х-Nd4�*���6#�tp��1��B�X +�'Bާ��H��Q$���V[�lh����J|d4YH����\9�JnV�/�,-����Ct�ދ�{�`U�*k/ �5Q\u�䮓&�>xXFE���_�i���^o����9z��� ��lC^-�����i����� �5�a�{��g�2�j�5~� �3�`�Z�jkl]���(>nǣƨ�4��V�>궏��Y�.Q,��<�c����`E����K2�<�$)j���ܝ���*�)ji�������4���X���`F��_�=�g'�:�����)|,��9�U-��s����nZ1��~�Y�A�BiQ#E-R�]$d|�r��53��w� ��F�Z���3�'_R��B,cW��ӕ����،�����^ YV����ፁ�Ɯҁ��Q�|�pl|EV��刳����p:�'\[Qo#|Ì �4f�IH)`Y+p��:+����Ġ B�C��^��w�ǚxk�S@ +ha�q�=>�ߟ����U�[���9 +�{m@ �Pf�਺ �L�[�d²��@/�y�?6&˻�"��H�97(cy�\���9�H����ïI��=�`��~%��@6I�ȯ���|��b�����Y�% ��e�9�*>`����u�QMk[1��_1�lcbz��֩Ih�����e���Z"K�j��P���{���ĥ'�jgv4����3jv���T�}�����ᬚ�*���KA#�!�Ԑ�y��e��L�Ye� 7ĕFƇ@�� +椑�cY�1�yEń">rˊy9^,�Ϝr��5\���j-i9�$�yFӆwR��A��$ݐI�c��T[�]��t���|ݭꍙ'Î +j){-����|I�:�K��򤊴��1�<�mz�yX�U�Dcm��2E�'�� +r� +�д�u���$�<N�J)̪��1�ʗ���?�5.Rߞ�)�hE�|���1�l{���KOz";O:�b߾B�TΒ��s��\��p��`���Г�z8�6I} MF����LJl�k\l�X�ɋ��1���� +�bo�PΪ_�o]�AOA ���+��p%I����� �]�q��L��1�w��@Ɐ_��:��>�"l��ha�o��I�&�� x�,�9X�mQ�k�42�Eʟ�w^�s}ܖH� 6�SQ�̖H���Ut=Ć�V�m�5T0��0�>SʁZ6Vp)j�m��ȟ�}*PO�����-�Q�:��UNq�� +����=�˧Ͳ]�So+�X~���C���.U��c�$[GX{[V����"�ԘF��ˣ���25�+�E�JG=7@G�X .,x��)��"~��6�k#��;�{� �&S�m~m��N�1��~�9B ��OZhD��E�� �r� ��خw�U}������~;���w5Tx�d�D[t�]�*ezq<���| Q�����j���p�g{bV�S��Aq�q�2�>���M�2�������)��fܲ�a"��U ��&� l�p%k�ˮ�ɋ�Mi�@�zJp��#��c"�Uik���S�D+�&r������?��G�}0 V���ًۨ:��қ#\���&�5�ZG���a���Y��1]��α���1.Y|��N���Sf/Q�2P�2E7���]�S�����̊).�/������,5ś�A�l�/��S\��]�MKC1E��wiKiqݪ�R� R�˂�y��`^2������Uۂ��̝��]��` ]�v���Lrs��Qߠ�7ς���E�������ј�|(��W��� ��O**��i�9������e�D-L���gJ9P'�� +.E-�i5� |L� u�9��;�B�X��X�ȁ��L����b6YͻU�b�bg�oUرzhW^R[���Tyd�mH�u���e���Y���i����1.X��1R9s�^)V�� +nr��� +.��|�]��N�@ ��<�P�Aҧ���8��%����z�ON��(B����|�[��B�)Ti�=s!4��̸.xH(����Ǯï��|�םU�F����s>2�ORc���%���D�Qő�Nȩ5�4#�l���W*$\c���B�JM��������aX�s\�I��夯,C;� ld/��J�P:�ש�L'�g�-J���p� ~4�m#��P�KNu=O�7]�AKA ���+��C�H�W[�Z*D +�(�t6� Ng�L�Z��.�m=x +I��͛L�Ϩ�+4(*��]����pbƕA�W� d+��`���F=1O� �����^"�!��A�S+�f�s>���k�آl#��%��� ��3��ac �� +oZMRN��I��д!���wt`G�86IvV9�K�@�>�����r�xY/�U�1�V��5���سzhg��V���lyl��Q��V��2��?�6<1���4]s�v;���&���qU�f�%��?n��(wO?a�>�vءi��zؒ�����-.�1^�N̏��V�o�6~�_q-�J2��gɌd+Vd�:�% �:YDhR;Rv�5��@�eYv��zɻ�>~�����<�!A.ah, ngv���\D���pC�+R!�����§L��l�b�� �Ef!�ܐB�E2��d \2Rx=��g ^����X���\�z�:�rԹDgL%���$��d*�;M`3���x�� �P��%�B�r�� ��������Ϸ.�ߘ͘�53�Sbaka3�n�F��N�-�[��G��1���xE�L��q�w����f���> c͸o� #�u�����δ�I(�vg-IT���͍%�-pɌ�_Q!19�����%.QY�Կ����W�����3n�n>'�b�D���A9]̥�[�ٌke,܆Q�}'N�ӫ�&�p]C���۽�dIrC�‘�wS-���"�J�� ��U��{�������mFz�(q���Ǩ��{i�%��T �Ɋ��Ce +�{m�Z�Rp+�"��+�}���u������L��Cݒ"���ш�)'�P��s��~�b�d$�i��C��:vZ�^�w�}��'y��� +H�r�0�F1j�s�z�5���qc��1 )�LCA���]�*<�E,e��.3���@�Ή���h�%p�m�����=n�6���%*��fcQdʂ� "�RŶ��J{�R��Ғs�-��挢�L�R��0)&Pp$�b�wy�V���k[�5f2b`O4$L�X���� �m^�RQ*���@�uA(�]F�J>8E���APj�MP�D)�����a|���R�ޞ.&���r�5�v[���b<�EET]tfɊ�r��ɥ�e� +�*bF���a����u�z3H"jW�(L?���Q$�!aT^�� �[�h�!4ua �К��h +�d�oЮ��˥g�������E�o�eD��줢)l����T��h�>�M�D8]L��^�R�9����E�χ��� vR��@)G�C��~�d_�úqv9� p�gxn��^xv#�֢>�>|�g�h2�<1�����f�a���v�L��y�;I�+o�V���G�Z}���<�ڡi�������0Cg������m� >ESZ�;����� } �wC �;�DE8kG�������j���U�@�w\�w�O[_�Kz�/~���nx!C������MZ�����|�z�礥�nE�p�uѦ����W�n�8}�W�.,'v��e�)6@6)��/m��X""�*I� 6��/�u���ˢ~����9�3C��,� �0%}� Ճz�P'��w|��|N��M���|��#L�Ϟ�~8�w�!�O {D�$���|Z�Ex6�;��(a�'�(�T�Y�!�Rԁ@X!gJ�i���n�\�Jfy�BX���S"��͸�E9B�"� �K3�������RCa*! +�DBD�] #XR����%�E��|�12G���cB��n�~�҉��Rsc�^B�35���LP�f�Q%Rd��|*���������9���S���x^�)���Q*��8>8��@� Ϛ��]��#"^L�z$e��q ��'�������� ��iJõ懇�3�D*��7�N����Ό���~ +I��n�|�3��V��0\����[u͈��_p��Ii ��`\�^^&:�|�XB� >)P�d�k56,FeÜQŏ��H���� �������l ����x�Yl����KD�7���I g�Jܴ@� ���mCg� �p2���������MZ:�.TK�q���v��Bw 2��2k#Eט�q>G��5�5W�]���0: әFY���ѿ�@��D��n%�z�U����9�����jF +T�`��ݯx��]S�-;Fѵ�*����N4�� +�usG��D�m����p�s���� +ٯ��iq����F�t/����߮��<�)��F�t�>���]���o��a��ڃ1,8�Z֖I���Re��l6ڝ[k�[y�NK���ihs odX���5���+� )�,�Z|mk�ֺ�ȩ@���9nT�W���5,}x#�`���q�����t�c�}��QkN�[U�z��~G���qx���<"J��ȱ3���;�0K|�P�Tx�0�\�aB��6���D���W���H�� �Y���t�.�}"��M^�IX���~5�_ �a��V?l�4{ �&�*������nn&����{�P�% 4��N�{_�_>e�?��AB� �}:�z~�h���E���~�*��9pn.�Ψ���LP��E�}?�ޠ�V�˕9��&%��yTʬ�ҖT � +((�ԡ��f�{hZ�_(%���c`孼��O�8���O\Q� ���I Sf:P� +�����m�I���P�.��ʎ�:NR�v��c$4�����{��y +1�ı/$'� �S�E7���lu` ��D��$��q l +�s��u@c���\�0�����K���}��.�=���HH�(�� s� ��O�<�,M�BDc����g�qa.F8]�WEX;�Hf�����a�Ɍ������oFLj$8^�N�>T�{lRJ����(���-�}��;�(AB�$�s���f� �L�OË/Ї�� �ف������.O/��pr5�8�>�6�s�GWW����? ������/����x<8?�>�؂9�L.&Ї�Z����`\b��k<:� �G���`t6T��U���ōjײ����q8�9���Ї�6��-��8�����EH2��������I~��P]d2�d ��c��l���x��J� ���J6��fX�Ix~^�[�R�6~��a����H�A�8�-L�+���V�{Z�m�([� 5uj�p K�р�����gg��H �O� + +7W*�EH8�F� +j +���Ӈ�Ѥ³t���F�֝���]�3�{@��l&���UQAdI�~�߄#���IF%Y����Ljẖ̸z���ޞ.�+�g������ų����A��bΖ%���-���ʠ��fX��"syi��z�N�� ��k�h��� �f�z`N�Ib�j���K&*�e������t�o�����6� ]�yeM^Y�WV�V^;ww��r�|�J~ո4Н�L׽�i�꩘��j�{��#t�E���@5�=]� �8؃{��L(��#���e����rVkKRѸ�{��Hl�t� ���RO�����ƛ�7��<%�w�A� �Nْzn��q��RD������s��[YB};���f� ���"E-@O�=��ܙ=X�G@W�Q �%X��UĄ�5Dz�Q�jn��� ��G�a +}3O�f����h4 ���;�~�]˫Ed�W�[.��~ ����y-3��g{�x��ߌ�W�Í_į=�"i��7�Q�����6e#U��ݐ�n���+$N]|}�����ey����s*�J���yqX�e\�mY��׈��2�h���7cc�=���:��L��@���A�*y��Ǐ�~-���rD�M�S�y^�X��wW�r Z5f�!��~[ B��^��(L�'XS��nv�`ɉ�:իni�Um�Qd���������n�߸���^�[I�q�ϩi.�t���L#�i����NY���ZI�4������m��f}�{1i����z��Գ0k+��V���z{wM��gE켨%}��s�<�(n~|B�?��k�z�)x�t��3&�v�+;�K����� +���@�����H[Z ����rf�z��-��e{,%(��1��@25B��x�3����% [���c$�E�wKo�6l�[��\����Yo:�\[?jT y�CVk�j>7صu��i��o��ބ4�Ѭ�XPQa���ڒ�WS6[��[���Z]�6S�6�����\��L�.Ԗ��+�>��|�+{?[���X`�l̑�Y�b����mE2��"q�����CW[�\�(�kst�����ryS��Q�*\���c����~z^YZyFLj�j���Bd6}fǣ�� i��>�E��=j�du?�Ρ�Hj-����B��g�Ro +�7DXEj�p��_ަ�6z��§BΟ^neº����X_�u� ˹vR�"�"@&��*˶}�n�h����Z�Nr�����t�n����'p9���^ꦪWS ��^�4'q�xa�}�m�RͲ��s��Q�JCA ��W��C[���Vm- "�z$o_^7��]v�Z����V�If23��6�����̃�Y���1q��N�xd0³��F1��VMo�8��WL�4� '�^���$�bt��C�m���"J�Zrd���/�[Rd ���&�o�{3���,� B.������h����μ�ȃ<&�B,$���1C�cxH�/=("nu�3b�<�k�n$S_ѐ�+f.W���c��+fI0b��l��̒ u&�Sp�ȈUN��*�;m��8��>������B�ڤ��Vc�$2���-ν�������A�(a[f!�̅l%@N�չ�\G�䉧X�6c�!a�^.�y^n/�]f����Yg�L�m�����ILQ���d��uNɧT�j�5�4+�ˍj�?`2�r� |J�;'d4)�3#6�ξ��3�/~a�����drN�\VP����?=�C�:g�$�H����v��v`�`⶟�^�Y�  ^T�hI���H�L�p ++�e3Ͽ9���v:�'��UbZ�g�hK��o��/�x4; ��$G���bQ@e��r�=)7�>x��:W����-u ����- x��c�ĝ4z�4dE{�a��!xU�yii �,�{ +��p�f�����SF������a��K+���KgNC�z[,���i�S��JC����f���V^���X�6L�h�R��q���eɐ�z�&���zA�#��0���bVp�������T$��E�7ָ��O����`����~߿���Ŵb���&���6��[AV�S��̑9�c�t���k�*�����G'Q��� :??���$j^���9��K}��N��O��g����S�n�0��+��K��N�$n�Z)�����$�\�1��{AY�ɩ4�&I�o�k��n���g�L�Dj�=\��,�ܚRUq��J���%� p�[@T�eGj%�'��49_��"k�h�w{Ǵ�V���e�rKp!�JB��s��Gi�g +��}�}�a���<�Wk�gm�zq��^8;2��ݖ�v�9Bm��P]����q� +9�K�[��Wi� �}��$�<���W����C��Y�����[�f;���Ʒ#��i쾣/��E���^)�΅|ڑ�F�0�-=)S}S��-m�l4�� ��x�G"p=~^�~6M��F3|V�}����NqW>��� �fkR����2Uڿ�\ø��t��C>t��A�ϐ#X*��ۗ�K$^��[����H��;Sw��C�Ԋt��5��RMO1��Ẃ�$�C�6@C#�"U nm�&��ت׶ff����^y� @U��em�7�޼����2Td2�D�[}��Lr�~<5��w^���� dd�Tí�+:1�1�)?�_:���%G�O�Ob8C�4[�瓊.���(�1�j��L��Yv�RT������_��X����:�� �N�������:q��S<��`�i��}��_��]�V�`�Pa����U���@��Z�6U�ȧ&bC���:����KdjL+�W�E$��ZO��E`����+]���)�~ �Ɂ�*0��mN'���ȷE���� +��w�LM_�}a����~�aŖ�m�.����l���Z!3>�.�:(I_ P8�О̛:K�b��z����1�%T�A�`(׉ ���P��~��5���Cya��YZ��a���A�ӽ�'��m�qZC�u7��/Ky����o�~ *������5��S� +{�R��"Vn��۲k B}O�]P�j#1��+�Oȃ\�^�a��!�s��B���X"�$�=q̒_4�C�N�]=��.�c��D�x�O��,�Λ�9;28£���d*��c�� ���E���7N1� �Jd\��\T0���=̧Ϗ��D=E�� fr.�˜r�J�6E-�4��M���gzeo9 +��>�-�O�90 ���n��/7�j5SG� :/�Y�a��AkyIC� ��C�3i˒�2V��2�/25f�O��^�Ey;~�dj� $���Z +���6,R����;�7���\�����C��6��Ɏ%'�(J!pW�����8,�aV_aJ�F=�5mN�� W��0(�Hݤ��o���uQMo�@��Ẃ��HP�@hZJT��B%Js�������Z�cST�W�uhs��x;y�Ǫ� 'cQ( *lt����͇l� � ���[P�(��%7t�@���� �-R��'q�-�g 0Aqt�9��9M�� et�j��S�*+�t9�TxS��p$��Z��`��mِ � +/;T�n�%  Ӿ�w��Ϳ��qTkLKT�c���+�g-A���k1��'����B��`Y�,��v#�$�ùtǖV���k��e��?����μ *�N�(�d�$�bp� �v���μ+x �K��.ʿ�a�� +�]��ݎ�FѱW 7�=��'��zc�@Q;��i%�Fӧ���gZ����k����U���2P��hԥC���l|�ы���v���r����W2��g�[Ҹ�� ��<� z�M��n۱ ��� �մ;4k��dQ��%j���e��^��m���Q/�4�N�_�?�SMo�0 ��Wp@��A>���f]�+Pl:�;(���ʒ@�ɂ��}�'n��t��G>�'��/=䨍bL�0iy���p�1�$�~}�YR�� ��\�V8J�A̜�0-K�Tg��-µQ�Y\(�x�hϣ�x�� +B��7���"��+_zt�`��9hg�iQ��#�u R"�1���mH� d Ǖrvޠ ++�u�w7���pK5¤Tk �����$%H\�A����9d1%͸��P�#�o'�3�P�˓ҽ�Q�o~�o��R�= ߥhA;��w�&��TQOA~�_1Mh8J�*jB�Ѣ��>XC��9n㲻ٝI�o�8�8I�>@��f�������,$$:�=;)x�+K��K�u��a�I�T҃E�`R��䂎#(cWN�2�X���i��B�B�=���t1��>N�4E�5\QNN����f��U��:a4;9��8_6�fpF��J��vh%iO uj�Y��=�BҲȻ� G�P��2,�C"��%������N�l$w#�s��}����.&ҋ��^Z�΀��j�B� �JϾ���I��������$Tj�*�L/��B�a��='͗9g�S99������:�@��g���M�w7���S���V�$g��X�y�Ρ��z|�؟\>���)��.a&Ya �L��<��܋��n�  tUa�U� ���4�O���M&�� ������R~8����y% +g�>�v�[�> �4KQlR�D� ���ԭ��*�d +��q �'���T�hUɆ�s�!E婷���*��Ž�3�?�I�*��uz*I<��$w��u�6\p��r�G���/i�����S܏��Yj}�Ʀ@}�Wд����-n� �~�!5>�fgˬuЂ��a��0#�� �r~)Yd�US#�?W����A*{D���� +�ն�ڕ��Ϻ}BG�C�J1W���ΚÛ7��6K]3��g���-� �Y[o�6~��8�Z +�e{�7]�a�.h� �-��hQ#)����>��(�"e����%E~�~�ѫ��6�FFR �������:^L�N'p +�[*aM������vK���̎+�? ��*��ވ �F�?P( ����rU?��rw�"RQ���X��W�^�̷9��$K!�tU(.dE�;.@m�c�X�z7� f�fk.vDQ�� gH$ž�9�����ۻk eS[���HH�,ia +�TmAi�%/D����l��ʜ$�["n��F#�ɤ���,є�ʇ��Ewq�z�J(��#��d.h����?�x�p����oy�����s}�|����2�{� +w�K&������������;��gR B3uK�ԢL�J�$ +F�,����ٚn� ���)\�vL�����sA�D!�$f�~��tO��AͶb�h����!1�DE5O-&fA�!:q%���h�/8��.��:���TPD}���D<�K��Q6^S�8�j���6yt�IEC�'��8�w�g�R�oE�1>�=�i[��4���r��-�aW��?���R��H�O�}d �v p^���� *�P �!@�M��� a���9l���@U�l�Y�OπL�a^�ϗ�@����h�7O�a���ި*]ES-�t���3}J$Mk2�u�ٱEǶ�(? �M�2W�ys`6� �|I�4�D��� pS�`��ARA| �`�"� 4��!�xb���c���j1r��X)t��@���Q �a�D�S8��0��v�x�G���ؖ��R��*�M��✵���!�VK�@�"/_�s���3�0wP�����Sd�l� �4�`��e��{�[�(��l��=8_���r�{�7+�Y��m��6~->�P��ߣ��2��btmqS�s?ֆ��'4s"0S��%�W[�Roz�:_v\�}�w�œ���ռz�+�I&MFr�o�� �a?���hz���w����+X�"K�f�������/� �9�7��f��2|�[�e ��֗� $M�6[��M����1D�}lI 8��U?� ��6w`jѐ�ft@�K�H���q齥�`�U�K��T��c�LF�9!�S[�Z{.�����콧����"�k.�$[�Ӷ�ş��hzvf���)��������0�x���+������;T��v +��/{�9T�[&����]� ]Ӥ׫U�^\\@V0v���mw�k�`F:�y��d�k�!����u�?�ؠjZ�.�10���O���,][{�tmY��8����T>�^W�,�� a�1Euz�9�3��QZ*�^е��R�j]� ,� +l�wb��7s�H��V��|W l�G�v�d�Ωi<_R���+��C!��1 9���EwxУ�f_�Ku�ћh��Η$�1K��8s3�=����5��e���n4���L㬷�s�E��rϣ��_��g.��D��I¶'Cc��ͰWVSM��k���+o�� �C��%a�9�d\�\o!+�� +Й��-���׭�a0���(��{]N������4>�lw;i3b��s��ł�ո��a?������ ��������~R�oc%d�-��?���i��{�B0�����toHz�۟�j����t���/�%�o̭��-4M�{���}�G� �wH�*0�ɽ�PH����B���d�1|��Z�[}+~��\=�x�-.>m�HV��~�����j]�eK��1����mA�K�d!�O8�Z*hA����C��kuue��3��L����/ o���̺˃_6�tTbԏ�x���_}�^zrVJMٵ�`���+��iJa��{��֜~���:��!&�3}�`zOo���Zy��8�8��!!R�ˍ���.��Q�FS�A�q_�J�x���Xmo�8�ί�*P���r��v���M���m��K��8C�c[���N��';BR��O�?�3��h���&5#��b�� +N��0�� [�n �p� +S!��,���8��oA�i��"I "ށ/V!|�L=�%G�*<�,�c<9��0G�)��-��©I j#�S1p�ȊINں��\[�a�K |���PSm3FB�C0�Cx8 箯Fg�o�2 g�QX�2T�������p�7lm+�G�kލ �g����L>����yϵrdsNQ0�OUyU���b)��j���)�+�cP����S�?>�z'8�E�f�&oڈ�������R�RΚ�:kΧ:{q��ia�ld�K��*ע�'X��h B�~�NR����� ۝��Xإ��3@ R h����w�ų�p��&)�*XV�� �k >�����ofEڗ8�� =���H�]jB�Q�o��vE�) ��&��Z֦J�H���4���m ӟgr)t;��&�䔾����GYT�h���@�f��P�I�֜�wT =��޻��b7q�����q����LL���ȌOw�ƽyS"��s7�-fF[f�h� T�~*�)3�3���u�1)CO��4K�~y�:��u���3���9���j�5���?�R�K*� ����:^�/���~�n���(H�C�F<�v �.�Rj���w}1��*��s���l�1�0���Ŭ86f[/�6��Ntu�G:˘�,q� ��x +Q�i^Ʌlt;:��c��]Α�=rb��0�N��N���-�"'����*��[�r�� ��B��r��P�yB`C��5��RZ��ݞ!7at���O+}�Z�� ���C�v���}�1#6x�{ksG{��u���b�:Y�ew�0�h�v�������� ��ȧ�"�P�Q��}؜Y6Z�&&sp �:vpGxO�y�aӠ��w��8jl������Ch��;a>���q�����<]�F�TI�f=(���?��K���Vr)������(=띸|-g���Q{�Ƿ����zj��U�o�:~�_q*Q� �ޫ�'h�����v�jto�*��5c[� m��ծn�������oޙ�@�\2��#+8��֠K�N��� �<���BH��0K��5�� xL��Z�� b��{��%S�ђ�f����7�a�s�H0�X���߸3�Am$zG`*�Y1/H[W|�(GXR��{o)8*� �B�#���D��7!������l�S��(g� ���l�@�y� ����-_G�����rf?�o��q��R�Wg�P�����AH�m�*�G��9��z��fZ�\p�f��D +T�{��b���צq��0��=��QeGa������F�I��q)��Tq��K����p�قS�@܀8l�*Q$U���yʯn��[�8��NZ7�W���2dw�[�q�g�� ���G��Wn�';˪�����+�LFab��k� t6t���-k��&�ns榊�6�]ǼD�[V�Q��NOv�@ +ZtF{9�Ǽ�|!װ�,9��g�s��i�^k^���n�Q���W)����W�? r/����'@k����x�3�e��'c{%Q��sl�q�O'G�&#����0�Z6q�%���h�.��g�]4B����sǵ��0��'���;��K7*� �ˬ? ��enFV�e� ;�zO�����i��ۿ��Rb� +�'^�q�}��W�&�Z�hE�J�$z���ο��H[<��\���{��m|Ɵ�w>ݮ� +���9����_1ǧ������Z�ʣli�ܝ~Y�����IuϽ�ǃFگ�A#�ϺQ����l.������;�E��QMk1��W�C!��$-�y�6mp[C��R(Z��WT��̬]S���n���ԹI�>����e4�e*D�;���L2WV�����;/h} xA��H-:��+�q����S��'�������*�Y�tS�W }�`E��6��Ę���&w�R4ac����{M,φ_C;Bۇ��>��w��c�xcէ8Ad����yw����j1H�Ŵ���4^�����k�K��\j���M��lᡳ�L?����e��� Q���L\�-�Z�+c\�"Xĭ�7�.9����@����+oMz��,��&eb�>�W{Qڔ�S�g�a|��5S�8�O�v��e��|�����Ey�1 ����c�vr�5���6�> ��A��z��9S�����R8����T]O�@|���J��M�׆RH0M�A�PPt9�����:*��ʎ H����������?]� F�a�3)�^9�?��ݠ� +����(��<8A 6��Tͱ@��[�"5K�2�32=-�{8d�t�yn�xrc� +�J`��~S8u�C�4@&i ���l�W���S�$��V�@k%�xeK�`e�8��#�.��~��hT�1N�Bx��_ka �)pa�ۜ$����r'0"C�D�N �C�H7r_�ed� �H�&O���Ry�ݷ�XQ����D|��ڸ/���]�Y�*� �q���ù"�li� �D�Aj�=�+ۅ��\�5\2��C��7�Z�ZpJ�9�,Xɪ�)�.�j%���� �l�;�_�N����;x�I�]\��E�iL���]tvK�KP����l�[���Z�K�>�fcpu�� ����z��H!~��>����LXωS� ������5C��}��S 4�T��f֐�U�SF��fcd!�����Ƞ ��hT�k��-�u�7A��E�m��,�}�|�>w���Ֆ0�����?�?������ڟ�����DY^������p}�{ʜ+�h�{c�>�M|3�2�V�����2��7T׾O�L�6˄��ύI�ٮpc�"a��ذ���V�n�6}�W�$N��SGi�� �� �}�M�,biR��|A�/��-�N�]>Y�˙9sH���,� F��Ð�)�S�dH�O�agpҁxLA�4�"Ȅc� ܧj�g(U���a%bE%ưR�����N"H�-:F,�2!�S�n�ׂ�a�����H� �9��~��׊��m3�Q�[�"�CNm<Z��3�P�*��J�dC����C��m�밗�1uv%f��(#4H-����V�c�TΚ\3�����w`prWK�`�F������̩�`�.V�a�`r��� ��A�*U2��B�����V�+�c-qv1�3t�k;�����*�rȹ3`p�: �������C�ت�{�a�҂��M��b�K��B��-��w l[�5�3����y3AZ!���;��@��RA7v��Q{f�����U7_��A��n����Y���ث�^��ס�*���.��]l?���wU���7Y�������೅�.�-!�2�;%�)U��jWB�ʧ����Rڐ����,��id�u�9����t)�5�NHVK<�j'��h�E�C =��4���sk��y�r�}F5��^p�h�K" �csFE�,�H��]t}��_8}���Z�)X�n�K����.��b�K�D?0��!T�{�y�ȵ��?�e��yy̑���Z�ʽv�J=���J�3e����YF��&�_��݃U�@[�ը�/�����x��#!G�K�C�G��A�GN�EP���;�3�.[{��8�4�ϗ��_�? +6/5�ŵ⑍�7�2]�F������Ih�5�%lQQ����7dT�P���/�X�R9}�WtRP3��8ɾ손%�Y�J�„d�Py��Q!K�R�/��߷47����[��Q�Q��Ea��it i�G�����A��ׁ=� ��1�@�4��u�g�߁D�DEK�'!��wᓖǂ�G�d���F���?�`�#f�3 ���&_8��U$� +��J�棘�6��3��B�q,��w+-��� p9Vzʈ+كH 33��D�����r8����Q���@�M� �s +��ፊ��� ?r�#�M�|��� �#��A�+) ����w|q��柃����fxquY^ޞ^}�MWƱ�-p`Z����Kܐ�m�*�T[ ���ł<�S�OI� ����,B�LO� �K�P6V ��JzB���v���ɟ�U��ޤ�֮6����D�ו� �F��m�HsI���"�Q<�n�Hd֎Y�)T� b��1���^��3.p�4���\�OJ/� د)���'�3rƵ�S��:��=8�1��߲ͮFZ���;� 5���A'݌G���y^B+��V2�n��~v,��XX�D��N�%�߃# +��Wq�d��`&H׌�[u��S&���� �����{��SF��Ă�0���e�uv ����� } �涻����M�;*�(����Ӊ +��E�~��b^›r��'�H���a�2���"�Xt��0�T?�g.�$�N����|��7{� Y#�Z&���e3�o����k�ҹ�b�d��J�ެ2�P)%���2��K�s�4��Ϊd��U?�*ׅ�s}~q7�ί� �� [��:��ֺ +�����x�8��&s���\%�{>(ߔ~�rҞ�&V���lZO���h��k�X���^�W�d���@{�t�Ke��b  �\����5�O ѽE�KL9�&9?V{b돩[�ޫ�~�Q9�Zfo�����,s���4z�‹�Y�ܐ�j<-l- �e�^��Das��V��lQ1r"ٮk8�|� �&H�\2���ut��ro_�3dk��r�݃����8I4�˜)4�T�6k�Hn)���7�� ��4c\�u���uA�OmO�>KʛX�6s�jS�rU�gc��* ����*����y�Cm�M��N�*B͈�I�v��Bnۃ.6'�h�7m�yi|�n��X���c���=�l{zn.$�}����iL�I��w�r��4�Jv�17���7���X�j��1��\onX����V:�<7�����Qy��ތƵL�T�\'�.�E���Ɲ\u����遣���Z���'�X�yg(��o�|�IɄj�a^�</,�*��}0\�?���O�(�S5��>ߓm��!�!�?D��J' �P�X�]�aU?�V��FO��&�-��=��4�:v�����&��S��|�=q^lC�n>���p�*��t�R�~�|��ӏu‡(d��|����EL��@ $����jdE���NW�i������~�J#��d�*�2;����l�G�h]�����2������ť!&}�6��$��;�{j�S+��lD^��K�l�г<�/Am�$�rs'��5=�J��ߧ��E��JA���uLB0xN��1 �ǀLf{��ٙa�7?��.�s좪���=d�Q� ��@���w=g�����LF#�y�,ȶ(R�����e���^1pC,J$<?��`fK���2�Tt?Ɩ�V�m�3�T0��0�>Sʁ:#l��R���VS��§T��P�!���w����8֩4V9�1r +�ӱϽ������[Ճ����T,�]T������8�K�yb�mH�u���e�v�G�Ƹ`E�hկN�rw�+��*q�5Up�̷�E��JA���uLB0xN�h� �c@&����ٙa�7?��.�s좪���=d�Q� ��@���=g�����LF#�{�,ȶ(R�����E���{��!K$<?��`fK���2�Tt?ƆvV�m� �T0��0�>Sʁ:#l��R�»VS����T��P�!���w����8֩4V9�1r +�ӱϽ�˷Ͳ[Ճ����T,�]T������8�K�yb�mH�u���e���G�Ƹ`E�H�����(w'�NJ�l�79PCQW��|�E��JA���uLB0xN��1 �ǀLf{3��3�to~�]6s좪���=d�Q� ��@���=e�����LF#�{4,ȶ(R���=��Uʧ�;��!K$<?��`fK���2��t?ƚ�V�m� uT0��0�>Sʁz#l��R���NS����T���t!��������86��V9�1r +�=��{]V����_uSo+�Y~��Ɓ�C{xI]q�� ��Dےd�+o�2m���AՕP���nqt��3@G�X 6W��������e��E��JA���uLBH��1 �ǀLf{��ٙa�7?��.�s좪����g�Q� ��@���w=g�ۛ��LG#�y�,ȶ(R���M z�2�s���!J$<?��`nK���2O*�cK{+�6�Z*��EXd�)�@�6Vp)j�}���_�S*PO�����;w`GQ�T���9����^����vխ���[�� +*��.�pd��^R[���<5�6$�:��۲N��#3c\�"X�%�N�rw�+��*q�5Up�̷�E�AO1���+��xE�$Ɛ��� ��m,mәe!��nE���޼�fz�]�e�pO�x��z�,�7�I5T��yA�� 2E��v��� +g�<�S�N�3}<��x ?��`J%�lw�G�����D=Ed�zB����޻cp��R���r�D�B�:�sO�e����Ug0�Vq��:�w�8��^rǎ�r}A��d[�ba�-������1.ZT̙����_:*�Z�����Dj)��O�0�� E�AK1����ؖ��U��bA���fgM0M��l�"�w���� ߛ7o�����e�rp�����j�0��M�� (���·� b���7��1�8�M��*XZN��.zV��{��h� ��c)����B�D�A�T���V3�o�Cf�'4m�p�=��$����G�!�)J$+�S�n�=mכ���_5So��A~��F�C��[v��K�I�HR�#��m~>�0���s�l{�7=�9;*�A��R��ç�2�m�Ok1����"������T("أP���&4��̬(��e�����o�͛�C� �3�X�3�&�D<�� 5( �j�v��IgA����@#� ���ݻ�L�9����1�9м�գ���Q�Y�x��2�|��&��SB� +&ɮl%f�1\� �����׽��3��Bs���0D�ppt�̽���n٭��Gͨ_���щ�t�9��L�n��*�8iC�Z��q�H���������P���B���I�I� +��7�S@jK�L���(�؆ +3L +�o��KO��P_�u�Ak1���mR�^m'uhK =�X;�]Kbf֎)��e׻N(�.B3O�7�O��(��$��8����&�$ :����%�W���� ��n7��OQMoI����l�u�(��;�fs����6�Gk�U���}7�&$������ �����'z���=���oHak$�E�^�E�KkA���+�"JΚ�(�r��lo����0�냐�v㱋���z~�\BE֛L��V���Hno��b:*0«cA͞��d�"��:>Ф@�X�t���;�c�'o�'e�M�P^�IEwc�4�l�����\�����3„ +6�\����b�:B�z��޹=[ +B�P����H��L�>��^,7�e��SgG#�X~��‘�A;x�m�� ��!I����u�����F+�����YM�iy���[@'�P �W��䩡����U|?E�AO1�����@<��TcH�HbJw�N�Mg0��nv9�˛����6���\�������g&����td0«gÁ��l�"��x>�Ġo,S�,��7�]���`��m��؟�IE7clioE�F���� �޵;�B�X��X��ȁ�L�~�y�\�lWݩ^L�U��b�eQ�#��v���.Ug婉�!��6ޖu�����#���(w|�I)V��%�&j(��~�o�E�OO1�����@<��"*�<������n�tf��w7����y��mv�LЅz,���S&���O�x�0�����gd]����=�:�<�S�;'�>�J$�?�c�K���<�,� ���f�:�*��Y�e�)�@�:Z���m#��_�c*G��`��[w��"|�R����ȁ4��]�u9_����L�4�z��"��i�95�L�g䱊�&��VN�e�t�(e�f�Sl��N�CҖ��h(�瀎B�26��9PMQ�K}�E�AO1�����@<���$FI�HbJw�N�Mg0��nv9�˛����6���\�������g&����td0«gÁ��l�"��x>�Ġo,S�,��7�]���`��m��؟�IE7clioE�F���� �޵;�B�X��X��ȁ�L�~�i�\=oWݩ^L�U��b�eQ�#��v���.Ug婉�!��6ޖu������eur�;<�+��q�5Up �̷�E��JA���uLB0xN�hH0 �ǀtfz��ٙa�7?��.�s���?�f�eX6� +D�7����rw;�V�Q�ޜ�>0� SQ��|S�O,R>��3�c���@� +fT"��}c�~�-�I�S�3�\0��1�.sʁ� (Z���}���p� +�1�6�z��p��u* �Oq���q�|��^֋��vٽꋩ#ő��/�-�^�+/�-�a��T�T��L��qT�i�/2�*H�(J!����vy2�; >)G+�]-��� G\ͯ��E��JA���uLB0xN�h�$ �ǀtfz��ٙa�7?��.�s좪���=d�a�*<-�軞3���pZMFFxs^P����LE�jl�?�M�ޱH�\��S ��%2��O.*�Q�<�_���clyO��"V�r�L.�<��)haR�����"�ϩ@�nC��o������N�!�)���0��}�e�X�n�ݪL)�$�^~�����A;xIm1 ��yREjX2��QY�]��iU�@"X�oW$ny2��;�'�h����ᨂ��U}W?E�AO1���+��x%I�!��3�����6�Y����U�8/�͛o��eX6� +D�7������j8��� +#�8/�}`xA��H56�xR�w,S�,��)f�����̩D^������[ޓ���Gn�`.ga�]�wFP�0)j��VS��‡T��Q�!���w�� Ga�X�Ґ��ȁI��>��^����nU��GX/�]lq������I��<�"5,� c㨬Ӯ�Ȭ�L �あ��MX� �� �I9Z��"�&n8��"~U��E��jA���uT�HΚ�D�s�8ۛi����?B�=�&�c��Q5y�>�"l��ha�z�$��� x�,�9X�mQ�k�G�3���/�?����x.��l�SQ�ĖH��U�U�8ĆvV�m�+�`"Wc�}���A�X����wME���T��PB��������8֩4V9�!r +�#ө�[-g�ͼ}�So'+�X~YT���myI��.U��#mC��#��-˴�����~V��/,��gG����R�ۛ�M�PT���2��E�_KBA���S�GQz��#�B�G!ֽsݡ�������ǽe���̏s���gT�-�-��Cϙ���?1���5 �-�Tc��@#��1O�\x�=��C���`�'Lm�4�^�QEwC�ikE�F<Ӟ +�rf�gJ9Pk��\�Zx��T��� +��}p����Q�:��*�8Dd�p`:vw/���m�h_u��[�� +*�_U8�zh^Ҿ8�K�%��Dېd�+o�2m�F&Ƹ`E�ʻ��'G�@'�X 6W��������e��m�AkA ���+�!ۤ1��N�$84Ж@z yV�:�$�S�����q ��HO����Ki +*���Gj���PX�?��n:q��gu���($�\� ;�r���$l�ȏq+�q)�b1ł$�rs�_U|s�gސZ���ܲ`��²4�s�� A����$lZˢG�CXè��?�:�I!�Y^�BN�(�I���~��������YC�=)���+�5�.��V<���y���򌧆�1���;�*c��t�s>�*��������Շ�f�*=����d��$B��U����m�n���<�6��a��9�I�m4���y�.�l�n��ϖ'A!�d���n����m�7ώ{�y��J�{r{wE�KkB1���g�"J�ڗ�V("إPb2� �MBf�J�{���.�pΜ�f��]�%t�K�F�咉���5( ��<���YA��u�H#��1O�R���L�%fA�O*˜���p�G����A�x�B L�*V��Z|�C�@� GO�.���/6�E���'Ͱ������AZxNM1��y�����6���e���G&J����I��j�.�ej�]� ���Y(Z��&�:�) +�&~�o�E�Ok1����"J���V� +E{JLf��l2�������v�q�͛���˰d�.4`)�Ȼ\3���p��#�ޜgT><#�"HvΟh��9�)_��p���D�s��0�DZ�yb�a�=5��/�P��{a�]���F�haR�⏍����T �P5!������ E&�X�Rk�)��i&�<����f���W��L��5�z��"��i�95�L�=�TE]gm;��&��̔2A3c�d��hWC�=t��q�I�΁j�¸�_�[�E��JA���uLBH��1 �ǀLf{��ٙa�7?��.�s쏪����g�Q� ��@���w=g�ۛ��LG#�y�,ȶ(R���M z�2�s���!J$<?��`nK���2O*�cK{+�6�Z*��,�ϔr�N+����T�/�)�'�mp��:��(�u*�UNq�� +��t�}/���u��V���[�� +*��,�pd�Ю���8�Kե��Dېd�o�:���̌q���pur��@'�X vW�M�PT�~�o�E��JA���uLB0xN�h� �c@:������0ݛ�w��s쏪���=d�Q� Tx Z��=e�����LF#�;/�}`xA��H5����ƠW,R>��;�c���@� +fT"�w�����16�#QO/�r�L.`�]�wBP�`S��w��"�ϩ@�nC��O���[���N�!�)���0����u�X�m�ݪ��:RHPy9gq��W��Kj�e�T]*OL��%�e��U���c��a��,��sw ��+���|�7Up�����E��NA���uB �AE Fc�x$1�l/3qvf2�����fW�c�����}v�@�{��[��sf���O�x`0�����d*�Tc���G�b����S�l%2�O.*�R�<�^�Q�wC�yK��"�y�S��Yv�S� +A��MQ���5� |J��>���V��( �TR��90 ������,�����ꊩ#ő���,�p��myI�b6U��c�a�d+Ge�6�G&��@"|�]kw^�,���I9V���&n8�� +�̷�E�KkA���+�"JΚ�" A0G!���f��3�t�B�{�M��.�����m�5�` D ;}�S&����td0›gAÁ��l�"5X{��Ġw,R>�����D�C�� +�D���󤦛16TYQ�O�R�\��]��R�ac ���ZME� +S�zBӆ��޹;�B�ؤ���)��Y!�}�e�X�n�ݪL�U��f���V��%��\���S�$[GX{[Vi�df� V� +��<:����R�ۋĻhGQ��|�E�AO1�����@<���$��HbJw�N�Mg0��nv9��{�͛�m��` D ;}��Lr}5����`�Wς���E���|��A�X��Y��+n�� ���**��i�?ϓ�n���ފ��x�� +�r�gJ9Pg��\�Zx�j*�|H� u�?�sv���N���)��Y!��}�i�\=oWݪ��z�8ZA��ˢ +GV��Kj�#�T�+OM� I����Ӯ����^�G�N�rw�+��"q�5Up�̷�E�AO1�����@<���$��Hb��m�Mg0��nv9��{���mv�@���[}���r}5����`�W�� /�T����O z�2���ߝb`��+�q(~pQ��J���֩4�>�1r`����=������[Ճ�#ő���.�p�����X�M�yj"5,�,c㨬Ӯ���H/,)xu����'�X v�79p�Q��|�E��JA���u��I4"B�c@fg{��ٙa�7?��.�=vQ��_O�Ϩ�[h$Z�雞3���jbn� ���Y�p � ۢH ��tc08)� �{��]�D�S�� +��D�W�����1vTYQ�/�Q�T.�<�L)ꍰ��KQ W��"��ϩ@=��B��k�݁E!plRi�r�c�@V��[���nٯ��[�� +j��.�qd��^RW����|k�mI�u���e���G&Ƹ`E�"�f���Q����b-��K��@-E���rWv=�(��I�<��I���Xc����2�E�_KBA���8�*����%FB�`�$ĺwl���ef���{\�|��9s�7�� +j�� uԄ��۱�^_uGհW����� G+�C�`xG� +'�4���G0t|w��ѥOS��$���󠦛>��vj��!�X�¤�B�Dj�p���Ʉ׍eѿ‡,�@�41�����Ȟ�8m�l�qN}�HN ;��)�4�Ξ��v� ̂3읢f���{�k�57� >�g�a�ܖ�8OX'�:}dTU>:U�&mJ�bT��(�4�IM'�<��0��(Պ�E�m���d���U}W?E��jA���uT%gMb"J�CNBg{3Mfg�����w���XEuTM�Ϩ�[�'Z�點3��Mb��^= jd[����F]b����W�\%���TT0�%�lwѣ����Ί��x�=L�b̲ϔr�6+���n���p� +��}p��6�Q�:��*�8Dd�p`:vwϫ��e�h_u��[�� +*�_U8�zh[^Ҿ8�Kե��Dېd�ko�*m�E&Ƹ`E�F�kvi9P�89ʭ��b%�^-nr��� +���6?�S]k�@|ׯ��HƎ髝�i��Bu �|Z[G�w���v(���$K�dC��ܓ������O.s����cL��_��n>&�h<�`?2E�RA8�� +�3�ū��;�^�Zg �L�7_�0��3���o���gCX�R+a���ᚪ���Z�1�0)Hkثe���a����*�d==Tk%��2+�7��5Cp!lLJ���b���8 ;A�**ga +;�pX�l�%��i��82b��Dx΄�? E�Q�S�ed� HR8� �~=�$�(;!r^^���Ҹx!�M�O�HjA�=� ��\��J�'�q�=i7a�*0���YCO���2�Lj��H��rx� �h��r�a�W�wA����X,5�k9�`]7�"q��OЧ�a+���d�h&hQ,'I��Z�66d��!�l�.�!��l��ȹ7`pב�ͽ��Np�A/��^ˑ���� ��3owG7��]0��`\�ë�����<���1��֪�a���C�b4ò=IU��Z���ښ�w������-V~.�qѧ H-�P0����M��&��'�'�'��67i�����q��?�_o�����R՝��{���.����Q�1���W��}� .�*���&F7�R:���M{ K ��t��+:os���{��q�CER O��^I^��Q��ꏊaY���Z��&�'<î�P��h��u�65�'�x� ��'y oh���o+�`A+X ��c���Վ�Ӕ@SAZ�^�"[��{��5a��|rO�V�L (��~+XY3��$a�h߼�x?�Z̓T�k�؋�J�֋*���>��%Aڪ�<,��RpBj������QQH-B���d�� ��� +�%�;�L�&ɤ��j'�p#�v+L5*�i�8<�md��U�����xf+ʬ�+�$�����KiM`%��b�&������^?�J�M*��]~LN�\0�� q�t ��}�Ϡ�"JI!�����V��扣7ϥ'����x��$���O�LoX�-^b���o?�|x��s�Krmp�����)f�%�\>�5����c�m�[k1���W�B��&�k�K�ͅ�J ����0��F�Ihf���^$��R����f�ӏ�F4l:J\�&g�N�"���pZ�GF�j��u� "%Ehqk݂�+��������� q�<�#��� +N)y>�o�� 8Č�$���{N8�m�,��!v�A�� ^����l +~ + jm�u0��9�s��0�oCz u�"vL�X8^��˫/��lUSK�% '�Z�`��Bs��d&4ۖǕ��H�qk)݄e"Ӫ�%sy�+Ò��ߡ������{!19����Z穃�H3K�k ~T�����K����;g J��ެ �2xe��Y�=��<<� y^��O����:C��4�e�i����G��~�3�),7~A�k��գ�969�5j +�&�v��^��߶�kF�`\�Ե�_��Wƿ��9zGG���oVc���v�B�Wa,-���̾����}PJf��G��{���{�ʪ�m�[k1���W�B��&����m�@)���d�l$�HB3k'��"����Eh4��7#�}�&�!�T��%Y-w��?�폪��_�e��,#�$-n���a��1�)�{#�u�.��) �L%O���������L�X�qM%��&pM��D(�@/��: ���B�B�9�������`}҃�>�#ń��E�}�O�L'٪4&F ��X^բ +����%MСٴ<��z �Jn�J7�G�Ȩ�:�\^��0����PLt��D�{�1Y/���Z땃v�S���O�У�o����+���Y %V��ڐ�� y)�ﱧW��)^��J$]���k�]�������Q�,�� ����bRX0n�\9�d�ɣ��I�9�l +B:�w J��D�6�-m��bl�ն�_�fX�����9x�ڟ�'�{C�����B�Wa,M��^Ͽ����}(�Jf��Ó�q���~�s_m沪�}�Ao�0 ���<�`i�]�4�Zth�a(�a�-3�0E�H:A1��r�&��dQ��#�=��]��l@�J��Օ>g��uc&##����/�����ҕ�Aq��3�'�P�>q$� �� 9Ң=��:��aI-�z�pO=1��XXd�)�@E;�)*����r~N ��}`_�E��(>�oP}�cȁP��vCߗ�ۻ�˻b5,�v(�yٳ���WZ��Գ%��;�<17$-��C~H?�Dcz)sE[��P܊~��1[QF�`�� +ݣ8�hCQ��o0�`�E�2R|*�R�취Ż1�Z�oO��ʦ(ʽ���=��uy.�j�s��3}��®��潬T��-/�F�,`UO����L�s<����>�j��"�#.��ڔ�߶gaWg��Y���4_����m2'%[~���2z���w�y1u�Ak1 �����n �f�m�%%�R�c�h<�Xı]I�%����I7�қe}OOOۏ-5�3)��U�������z.NN�-�a��C#u� �I��<`!v���<$�*��I �:SyduÖ���p��G�p�=d.Tp�3+�v��j�qm�;*#b-�2�^��~� +O�i��ͽ�Y"cH��>�K-gh���‡E��nw�u�G-�<��@�Q�ՋG����:kd�:#_�BOl�"�>�����E6!Hq֩7n�~h�%œ\"��ľ���Z��/�/8�����yڄ�o:����:����ϙ���(�TO�}��%�Z�&�]�Ok1�����:�B�!�4�Hi Cr,��v�+"KB3ׄ|����M�ی�~��hq������̕hvV�u�X.�Lksvjp��� Z�N�(+b�e�^yn0(nc�e�����:ƍ���Y ʁ�Vc=o�� ��"QG?�猅����%��s�B�f��5f9���1��{أ{Q{g9Å6� ��a�䙄��x;�{�����xWP�`ڑbK���ދl�v�2��>[���8� �aIdˎ�}�=l�6���+�� ��̡���i] �I7$�^��qPg���?ʡ|j�H��; QRg�y�9n�څ%�lcn�� k��ҝa,��~za�����M�#/��?u��`��������������փ�}�N9*۲��k֧]���G}� � ˚��w�]�OKA ���)��V���ֿE� "�GA��lgp��lk���j=�[����2����a�Hx�&�۫�+���x�&��X��hcbDE%1��!n��aP�K�K��ȏq#�q�(���bF��z}�O�<��פ)�;��P���r��{!(7�%��ugE�x_m���W��9+#��;Y,�51)cy7�=.�wO˻~�`�v�h�����.Z���t��4��靵�g<�Ey>2u���|"U�2 �Mg��E?\�0΍�_��@�b�{|�e?46l�}����qy�+�C�:�8�M�Ɨ�r�]�OK1����f+R�j�*D +�(H��m�qff�E��eW�����e~�evUcEC!{����`����g�;=v8�*&E�2!)�Ci���&��ԝ�M4��7„�����3/L���y��� �i�ՒgG��7��~�����9�����7u�Ak1������LB��ۦ1(%��V(��ٕ�2�YS���n�Bs��{�ޛ�� +:�����4z�i�����j�.���bE#VRC�q��fb��Q� K��g�M"yb��-��u{z�w�q�n�Z$�Y����u �sI<� �೘�v�����6+,0�1%�����g��(}�g��e���*c�0���oʹj.f� ��b}���h6��yT��;U�pB�\ y�} ��?�l��b����#���K�_�ئ�я�dT1=.�k�bԴ�B�sڸ���.���[�Y��%���o�=�ZV�7�z�`�a�ꅅ����>�n�~�?�VQo�8~ϯ��x���K���I�^��3k];�'�j��~�I +����'������1W_�$��dCKFpZ�K���g��4`� +!�����I"6�)��t�b�:!yn�B��L}GC��Q�]�O1^7a�KfI0����-�i��N%: 0׊�Xf��� ��%�LJ�o�-Ge�Zi��HhՄT"��[��~�F����O�F�ebaw\�VP䒷:3��H�(��6ea�03������ ��,A�uz?�Nj�|>YD�^�O���a�"���]o��:����1�Ov���h|;��V�L�O{�YU���c��f���V����3#h����� <#�Z_#�c� + %�j�"�����V����.�4l�õ��!rɬ�(3~�F�f��@��-�Fl!�2#��1�S] EMx�_�lҩ�g����B� >!J##t�s�O��|��K?�5:Q��`�E�g�F�9��k���\|)^h�ŕ��J\�Z�E���r�o��n>��w���%_=:=ǟx<+���( ���� +Ԓ��b��}r��g�ca�R���Ak�AB^L�����L����H�)3�V�/?��Z�E�N��LJ� +�4_���_ʴp�I��Y��v䏦��#wFhH�g�}!�.u�ߵ��صk�����Δ�҃b&G��]z�.8��b�S�q��&9�GQ���R��w]7Х�������9ztlU���3v~Bbx�}������ ��['w�A��p�f)��kA��bZ�{�5���u�P(��c;����ɻ!V�������)(��5ܿ�^\��=� r_����ȯD=g?�5� O��{�~��W*H���E�]K1E��+�c[J�ϭZ-�D +�Q�iv��$df����eW�>������˨�*<-��^2���pf�#�^��>0� SQ�[�<1�eʗ�?�b`�x(��(~rQ��J�ž�'ߍ��=�z�Xs�s�Ev�S܂�X�����ME��O�@�nB���[:x�Q>֩H}�c��$���S���Y�^v��TWL)N$������ɫ���%5�2l���S����2���&�u��cu��[��Hk�|M�g�X�?�/�m~mQ�n1��W�C�(jĵ P��R PD� �ڳ��c[�q� +����ԓ�3o��{�}�]�eH�/*��w}�\^�Zl����_�/}`��L�H#�Ο��Ä�K�Y��)z��;�����-ؒD�����7+<�@E=E츲`[��mv�S܀�haRT�C�$���I��1�`�No�� ���qLr$�)��Sa�<����w����$L)�T`}��b��Wm�K�b&�Y�t��0���!}��t���2��N5�%�K�Q��?;�u�`�ѴQ�D�' ��78%o7݋��G_���z��^,��%ۮe(�YI͖� FIG�P,#KA_sHd�6�c 3��*#��Є���d�S�0�s�V�!�N��v�:u���X�o��EMnr�iڰ�׶K +W��7R +��W�E��NA���uB �AE c�x$1�l��qvf2�����fW�cW�����}��` �D ;}�s&���O�x`0��gÁ��l�"�X{>�Ƞs�S>������D�c�� +��D��.󨢻!6���l#�����\�Y��R�ac����5�+|J� �>�����Q�:��*�8Dd�p`:v���|�Y��:0�Vq���巋*Y=����/��RuA�h�la�mY�m���1.X,U�+INQhqr��C@'�X �W��������e��m��j1��z����]���;�Ӑ�@)�X0�v�U$13k㖼{���%{�43���ξ�6�!,S%���J���s=5���O�l| xA��H<�~G�}�]���VQ�� _����U0�i�Η ݌����6bA1f2\�s�)�@�66p)*�u������6]p'z��Q�����V}�c�@V;O���������}���*�V�xyeQ���Z�K��\j���3I����Z~H?��L��xEWȐ�>�fj�]��u +�n;m)�w�!���F��,�H�m����~g�p昚�d�L��S�޽�V+��(wN���]�T����ͻW\��(e/��,T�lC��AU}5x�A������;��ݧ�¹�\.ƃ˖�鐩�������֙9)��Nn�1��Լ���Vmo�F��_1'%g���S���8�KHc�1��Nidm`1��X��؉���j1�|�R���>��+3s�k��a7D k\0⊅x�1~� Z�n ����OB �C����>iA��i���2����o!��b&8�#�������=��G�A��38���eĘ�!�@@�.�#����g +�)`�0w�]�C��c �O�7$�z�q +�ש�d�ә!�R�D�����.�����t�ӄ�\��.�[��y�\ V�ؘ��Fd�j%\"#.@���r�9���o s� ���xbN �6m�9��wS9cs�BL̻��2���d|;V�( ��v��6���Lui٦c�����ڋ�̰��+սm8s{�أ���P�>�M���ˍ9S:V ,C�����z4sL�PFO8�ݘ�ѧN/n�����ȕ%�1�������p�+��I���)���?h��qz�B�F>Y��-�~� �+� J��Y��h,�Q1�O�0�'��$��C�+��T�  �����v0�"��q�!%^��YjV;\1)�����K�W�Ke�k� �$��'�;#L����K�f[���p�N��ovz&�tH�l��m�Ak1���+�!ۤ1�&N�6�$PJ�9�X;k�*���]J�{�ƛ�nzz�{3Z�_в�$P'�k��TQk�@~ϯ��D��O��z�,-���� �f4K��0;ѓ����1��ګpy���|�|��\|˳RR�b/��Ld����T0�c�!Y_0�i/>>�zz� vUA�ް���~H�9�"C?����� � +6�9L�3 x=���~��0C?ʴI�p�7���:/�b�$i��la��ӎpŨQ�D}�� ��TuF� +=�yr��L9۶6��(s���sMY����1�>�9I��mn@{���]ٸ��L��Iy����Xpޤ3~�d,���AY>�H�����Ǵo��k+t��2�*9�sX:�6�^���;#�[q���;��?��q���ۧ�f�I6Co��6�V��<�`�����.�'�.l��J' �@�׆�r/V��hb�Tn0������7�������Wỗ��~���V�r�6}�W�4$=��8N۱L5��Ԟ4��v���"�&��Y�r�$����7�K:�E�Erݧ�Ag���<�^�RL# �%�ع}�h��ԛ�y�w97�q�� hFT�9_�%�\�G���� � I�3��oH��)#����A��nq���L�%Hpj���:ר�@&SH����Udj�w���Y!$kv�{��=x�b������.J�����E�ry�u >� }�B�!.�d]��� W�v���k;],O69����S�ؠL�>��u��wVm@� �(U�`��j��vnc��eĥ <���鐱 �_���l� ˸�&�4��Sų?{ n��]���~�1>�Y �S-��(�Ó��V�APo����^��1���UR(���?0!�c8l��=�� � +�%p���������d��zp�Q�zkl����ՏZ)%���d����۲�� ۬��t����f{4#]���T��&o��k�� �i7A5!��K7����T����Ζ��ť�Ab���?��26_\�'�g�/����<Ѥ�M ;��h�V��m��QГ�c���}>tݷ;{�hn0A�rS<�����=K�S��Ao��=>h�株��� �I�FXK��|M +"�6|8�wb]֣����<:^���W;Y�9lݕ���dB1 ��[�m)-��B�7e�y��`G�Z���Y���L���z�k���_�:�}��m�Ep|�~��[�{_��T[o�0~ϯ8} ��:�c�Zi��h�&!�k�m�����>9$%�H�/��'|r����-Ϥ$�x����~�mGІ�\yȔFP� ��$WK���D���I�[��i�xQ[-9H�mŊ@٬�<� ��*������'2���.��s�}�&Y�dď{߷��z�^����J\d(ؓH�B�q���g����bF,z� +��`��0� ��ڬz8v�7A4ȭ��e�ʙ�����YF�y=4,��ZZH!����-��s�A ��&i��3��t��ar��)&z�;4�o�y�$��G��t�&&����>j���G�sۏ[�K�O~\U��~�`�Ҵ���!cyfڭ�t�{���� l�����1L�8N�l��Gi��� �~�o�_��Oo1���)�!@4��B(m��HQ%�r���f`G�ږgU�?I��G��O�a1���b����$EX��]h�!>'^V����k�o��?�T02�Ӥ��/�4��J#���'5�0��`�H!:�B?� ^���$[�!A+¢qv�Վ-y!�_�T������VL���������MF�Ŵ2���Y6^4ǚ�����d 6�w��75I4�pW�4 �ۍ ���w���5M�QS�<�Έ��(�r͊� z=LV&��fl���+�� ����0Qmس_����x*��M��b�x�����/���l� �o#�z�O�l��m�|.�&?�[B;���;���Y�ّLhOڶȷ��]����;��m��d��I����H��T�h��!�<�V����y&��x>������z���>_����KA ���W������W���RA��q$��v�ә!�m)��.�ZO^<&y���L/�Ϩ�RSq�f����dxV�*��쥠����LjH �^�<��+f)�U��0pC\kd���V0%�|�:ԓ�/�x��Xpˊi94��Ϝr�N�5\���j-i�1�M +� �׽Sq Cb�tC&)��Sal�w����l��4�P}0�d�QA-�ۋk��<� _R���R}�|\E�p��KOz�^���U�Dcm���,ςp4|T��U����� k����Ƹ�?�Gl��9b��g�R����0L��������s��4�܇q����M���rWf�ix��� |oܭ�/��=?;��G"�r�g�<�Κ|�Ey�r����&�ҙg(�3�Q.���J�U;������z`4�>�IR��Re9���)��۫�:�������h� +�f[��]2 �q��4쐽 ��鴕If/�N%X�y1YAY�xŘs]ۉP����ZŸm�^U%�͊Xl�����5�Z΋W��o�+T/*l�� q��Y���U^d=�o���O��x��0�6����[���n��AJT����x_S,kCt�D�%ا�yӚ�W��J�ʖȖ���/�O�V���|q����?������n�z5_��od�� +��%� 3���w}2��HL �I}������ҡ�����Q럛��$��1Q���E��� ޓ�7�V�o�8�_1��KRA�}��Rh9�^+�h��C[!�L�u���,���O�IH'�_Z�����L|}## ��(t�Q�7s����߽�sy��9�DTCH� �2 Bx��/H4FBn]F\߃���3��Ae4\��v���pЁ.�6�p��\�\p+#�B2��@x��F�El��Y�B��˜1���V�Q�F�<jE ��!�k�����a4����UR���� �P���6�D`l�Z��G�E��|�p�B-���� �Dz�k�ɵ����q<=�>�M^���������i��+i�Mf��`8�da�}[��v�B������n|�,�z�D3W� �.�T��0���(�8�Y��}���Sldlz��3�5L)_b�G�b����� Еd�Bn4������9ܮ�*ߜ_&WR�51-?���� 2<��C�D\7H�=Py ��]�Z�5Ї���D� F�=��y�D��-�U�)�%��S�r�2l�iY�u�1��`�R��}�5�ԵU� �����h�WŠ+ց�� YB �x̘w��k�Z +;j�|�X�<(�B�oE�D嶗hڝ�e��;�C�$����^Of���H�lm7_Bk�&A�;�V+�حa�+�,��g2�+�L��i��� �B�G�f�e�,�1< ZT��t���@��f�~�{�Nb�k�L��l5��C�f+�m�������8���{��=Ӟ���+�e�Q�Z�u,*��|f�ع�v��,��1{�٘� �-��g��֮W�N�ܨw���Hv�c;i�*-��)@�c��ڃ?ş1j!� �+8�rLH�'jM��z^���*X���K?�|�_*`L��!b4�QPs%���ɚPF�L�z �Ts�g���H� p�@F�=��!�Rd@�ꘙ ���-Scy�.�R����cK�>���(��>(���P���F9x+�>�mQ�H�]�ǀ{�?cTۻɬ<������g��p�U�ꃖ�<7�,�FrkX�L供��Y������0R�v����E(���3���oʵ����@���o�]Z)'Yv��4�f���j���@�=��G 4���cS}1V>I��[��V�BH�%p�jo�a2� ���T����Y���8�!�yle6�[����o��!^ �B��ݧ�8�s��X�o�6���6x�8v���S'�<1�� ��fC�-�4���cc��������֭������x<��e��#�Da��b���6E=z�w'8���iX0��4�D� �M��pc�n[&B�;%~�D|Fe4�%J����?Ƌ��3цט���z�p�&)ʔ�e"b�RŞ3#�. �� +L���8ZZ�ܜQ���T+b�=H9��f���n���ǻ�U�3 1�B4�L�0�f06x-3E��w!:��P��"�&DM�'��y��i뗠�2��v΄A����}�ϸ���L�̸I���[eb�x˫�6����S�����x�*&��_5�H._Py���[��)]x�+1x�V8]�2C���r�5�3ů�Iǜ�0�V)� +����g`prWk���X�[Z�-)UlM B����NS���Ur�P�k"b��%�6龊�["��>��8�2�'m�А�_.U-NE ް3�HbTF���Z ��W��3g�J�|N��FeԄ��~5 �l��W�����kh���/�jG���ٯk7��E�&(�Q�����Y�ܭl��/�2P:� |-A��O��$J���7�PL-wA�6A��:l9���%�eF����6C�JۉZ`8WGE9y�BO�zjT�&K-�S� �h/���(� M��/2��c�n�]�?�Ae�Kn�t��m���� �٩��.��W�z�uz� Q&��ژ�_�θ���u��� ���Ÿ�>�xJY������x ;���O�B�]�� ]ܤH ƿ�Q,)���{i��Q�h�~�R�؆.c��kn�� 5be +���9;���g�_�j �<�4&ÆV�/��W�T���a�AҀ#��T�%��^}����T���g���.gۉ�C�=U�" �A��a.�'��5�0�{|��B9ez�&屛8o{�]��k�VsmK�,5 ��<V3HX�E���tBC2�����FL Y~hͦa �v�J]! �huV3U ~;�.g��4�D� zP��xQG΋W����}x�~�"������؟��o7WT�_�� a-Y��w[� fj����;W�a��2��R�ΎFac\���xI��b(ڇأ��A�nv��!E �w���������[Yu���aTi~� �G��`�8�(�~� B�za�aݛ�n"��7��������;o���I ��|�ʰ��%�4�z��cM�=���_�9�߱�J������Z�5����.�* �C0|������Z��|���2��06F[oG<�WHۑ�zl���-/ݣuS����@�#c +� �-�R!�I��YK���f}�WՎ�����z(w{޵z��ƈF�IW��J���I�o������c7C����ТAn�6r�vm-=�.������*&�� u1ߝ�W֐'5��av3�����o'��|<��O�O���'� ����ZmwH�|��Y����V��]��Pk��0��—ľ��<vt��n{��C٥?�O�G��U��1�>#�� +�а��we�����4���>v�_��! �Q�Ŷ�����͟� + @�+�Oq�B��"(�B�ؑZ�V?!�M_� �T(��Q��~bVt�~�� |�R��U�<�|vփ�go����;}1��P������>�B`��j8(��Di�y�� ���R<�����y�l^.�bh��'�������a3k%u�:>��v�0^ﯻ��v��Q�3\&�X�4��6)��!�jO��^�WG~*y�a�H�RE�^*���c�Maq3}y�>p�(@x�}�H�'f�h=��Um����������?m�AOA ���+����P�`4!�D����ٮ�8�L�]����U�Ɐ�}�:��>�&l��ha��z�$���Č� ���Y�p � ۢH ֞w44����߼b��pS"�6��NES["ͫc=���OTYQ���R�T��<�L)ꌰ��KQ W��"��w�@=�iC��K�܁E!plR�Z�/�Y!�����a�||Zv�z0�V�����'�j�Y=����Gp�>"�L�[�la�myH��#c\�"X���[[����G�;��k��$�6�RT�I�4��*��> �ǴJ�� ����Rf���/� =�KKCA ���+β-Eqk�T,��R����Np:3$�-E��r��]'9�2��������HM8؇�*���x�.'�EV����^ ��:�.Ţԓ�.Fa�Ʉ���'�)�^2�o��EC�Slh���g�EBۥ���ޫ�J���{㒧���L�a�e�X�n���̢7��a���G���t�4g�K�����@XG/��>|d�g#i� e�I���v��m�C�nL8�F�k��ܷ�u�AkA ���+��6&�׮�� ) �S!��j=��A�Ƙ��^Ɖ�Kr�����s���fj���XI?}�w�r���Ȋ��Ջ�����H'�ԣ�.fa�/� _��HL��iݟ������R���g|��+=�5V*5Q��P� ���g�oE`�0N)!��7:q���c��7.y���+��p��q{}��޴S�`���� 8�EX �e�@e8G�t��I������>}�snҗ�=�r���9��Hƶ���<�uP�>q�8���u;�Z�h��?�/%u�MrG�|���J�����y׹�?}�Ao1���+�!@4��)�*RUEMnU�w`��ςP��^y�%i�vo���=��ɇXE�l ���5�]O���}\�x�l��:�M�$���}e|]�q,B<��U���c.��ё��� ϳMw�.�v��PRK��f�$u�Y�"��8A�� ^�nj �΁��@+ƶv撞����a�6Ȟ�?DtL�q�|l�}Y.�>�eTSL+R)�����G�4�O��0��*� +O{N� �"Y��f#㢨S~�79&�^��l.B����iG����q{���n'�#=��,���QJ��M�Ep��$�����5�`�o��Y�h0��@ҁV��)+Q�!���U�X��E+�g�K=*�ޙp�п�!�������w�p����7������7�^_񄵖N���/p��m$c_m�-�����Ϩ���T���0��+�@tQ���Ң]i�Z�����qb�ؖgB��{e���֗$�{o潱2�� +9J-<�����Cz�<�f�Q#�Y(����� �`��V��g �N^� +���7o�ka~�g������>��1�p#��0�K�0�zc� +��i @&i {�)�z� +>[\ lK�A6�Z+����Z�����(��y/�����)HEc\�� ��kaG�p0O��Aڼ�<Ɍ�#9!� +��=&2Ͳ���g�qu"�}| �i��zR����-�!�B�f�Ԃ��Xh�y`�� `2�� <f �Ϋ�`��s �ЪB�U�~��Mޥ�D�p��+�:�������6��.@t�F+ ���@��Z���A�Ue�7�u ���r�Z��s���Y��[�j|a݅+��12��C=���oD��밒����:���U[�iu��`b�<���q{h;�W����K=�K:��������$�l�T�����k$�U��p_�����T��2�5�S��N����z�j�i�g���m�Ak1�����1��N�4��PJ�=�X;�*Kb4kJ�{�ڛ�.Bo��73�Ϲ�h�R�S񶳗����|��C���tR�I ��S/G�q)��<�����^#�K���� +V�����}���5���bB�x`ŪL�:��S\���§h*����K�פ��� !���Wwϱ0$vId��5r`*���i��}���c�XQ�`֓�D��s�8���:|I�z�O�4��E:p��O=�&�7�t�*e�P�r�G;����I'���`�4XIQ��seW9��WT)K7y� ֙�ӧ��R��}�n��.��O���fg���A=Wu�w��۷�Zzu��Qَٳ����8e4��N�W����n�0��|�9�`n�^k'u�h�"⶧M�,�4IpW6���^P�&�u�~3�Z��MDE��D#�d���!_���l�0���2j��u�w��ӹB�� +�!�m#�1�%Ox��NI �<-7�����)V��,V{|��\��D +�QB� +&xIv�JH�~ ���9��=��5�`}�N� ~��H3ao����tsu}��Ψ��4ZpЌ��U8Xi �<�6� U�b� +�uya��ʌ�1P)�b��H�� ��"$9�@���E��H��ä@Ƒh�-Ý�{|��-��l+'̤���h��>�1�I�X�Z�"P��G� ���R��7��$�r�/�3�O/���}�%�����4���|��\ +ma�L��r�5̥H�:W����}�m��C�-S{9SlK ��ClTmO���9翊>A5��1�:O��\R7œUV�R�(W��_I�lv +`��8��������:�95]��p��8�WCCǎ��ҧ��:U�w��bJ���S�d��5�[�".v]ڌo�6�5-��@�,�DDe�Z[f�Q�uWi3�@[ . �s� <���؟��͂l���I8ڨ��JT�<�*���f�m���>���>�L��y`����Y*l�F�1� +� +7�@�����5�^5jv92 p�Ƨ�q�� ��N�8�Bc���8�+GA� � �֨̐%C�r�rڒ�bNM���M+�y1=<��S� � �B)я�,!߫��?�O��?�N�F��sS���YH�25�� ������R�yK���&�W^b�P�������GY�(_8�Ct��x����zm2K��2��L�?�g�����o�U]o�0}ϯ��*�k)��j�J]U�iO��qn�5ǎ�(���'�$$�t<,�����s�Irs�%D�%3Z2�ӊ��٧�4� ��DX��D2ft /���8����ވMB�>|6 +�d��pÌ�ź�G8��̒` +�b�nlyc�%�L�Sp�ȈuN�آ�6@ B�K ����RpTA�X����j�Df�w~�������ޕ��(a;f!�� #� J��x�s���Jɓ@�m�8�K�̣���An/�]g_}��’���� $.��0����oL�-U'�>i��s��1s��h�Ъ����Z� ���`�-3��Q'��Ό�2B�r^L�&�(w��Vmp�� 6��4�*��O+6�Qn�A� ��E��,_K���Y��V�L�),�yÊx�tx��� ���3O�_��+��ܕ��1+�k�}$πv���p�s ����;������g�bؿ.cqTm�r����U�p�U+�U�������+��U�h�[-g�e21k��H�#29�"߳��c�L��� ܑ[k-;ɝ��avY������;<��_,���A�w2XC����)��wxF�p�$��5T!���H��1����z7 ��;����K;l�e 3דIƍ��0��E��6Fsf��İ��ԛ���k*{�Z��N���<�)&�o ���帾��N]��2���g�;>Fp��mu�,��� �Ѹ7��CW�����[��U�O�0~�_q��h+J�וB�TM��{��\�B,\;�9�������W�����ƹ����|=9K�B��5��{�� M>���h��ǂ A$�X���b��xąN��x�-�x΍B�*�zDc N�Q8]���O�`�KFV0ט���?L�8A�Ht@`*��5b�Zm(#��l��R/�Z +�����Y1+�:�D"#�������\\~�_�P^���� #m�0���1X'�tj8�a.y(�BJG�����?}E�A���o����c���Odq�_]��4$��/�"k�Pv\2"��_)���y��`4�t��6J�ʊH�q9:sbĚY�Q����c���n��!��f���J���פ͕���ֲ^�Gt󘁓t)�(U܅��{�sL��y�{j�����46��*z�%�]脉/H��B e0��IBo�gS��7���2��0��~ ߐ��-�����ij]n�lB%���5t���.��><�7�m��^�K��e� �Ԩf�v����66zC�� �}y�K�(O�*�"�^�iB�e��߲�S���yWrw��nʴ{��*����;�����a���_��_�^� #����ݬ&��&fT4�_��)jmeIV�R,������ k��Ͱ�oV� ��jY'ϕ?���\ ;�К�ܧ���gJcF� �Y�"֧�vG�A{�H��4B�>�ͭ�����t ?��5B=8���0��������R�}�?/�S�n1|���Jy��ڄ@Q%RE��S���Ϊ���5i���+w��^�xfgf�j�9j�{,d�<�K@�_f� �0 Kc CP$���P� �gP"n|x!�*z���!|���F�+E����y��C��B���#\q}0 E@,& (���N�,�x�J�'�a�ݨ'�5#���Vb�B��ac����fv?�%�ҘJ�Y1䆷Z�ó�$�gI#h�ז/2���Ai��Bѝ�U&r�e����Hl���/�L[� ��'��;n3�`q�Nꣿ��`Ӎ"�(�r:d6J�6 �< �Hv�v�.Z��Vq��?�`�vo���j�JJ���aج��H��L�� ��tj���w,��*�Rc�R'0l<'�C��?�0.G¤t�c�z֯bO��T��:��G0�v@� �i���d�MV���tF��w{~�`a8�j���t;��vFԙ�/Tc!=��ʊb�)aB����Y����В�����lOl�,!���|0�b���d�pttj�}}���yHRM0-��d��v�89-�)�Ě-�Ƽ�<͂9�T��JÏ�g��<�j�@k�is�Cs�������ϳ�z#�g��:Lu7���R��z"|nJ6�ugE�'�,�.%�����8PV�ȫ7.�5�W�;�f����w�Eo5�� �hX�����-���Z: �P�]�#��+i��p�ܔ��#�8I�/V�lI�([�->�n�8��r��3ْ�u�]�[Gj����{��O�#���h�O��V�n�F}�W�H���Kd9v\�IP����1�9�^�;K�D�/�]��qw�rΙ١��y��SM�c�N���W����t09���J�P��9��m�V|:@mqe�ʩe��#\:����<��3r�/���4���<'� >r�g�m\y��� A&Cj�wj^z�M��u�9cQj�t�=Xk���2 �^�+k�I+�����OW�7��!TM���&A�����������ҥ��f���� KA)�6'��~���\& ���9G�t[ʹx�l���e͗OfEZe�����k��N�T�~Q^��� +�[WA��_�x�}�a��LNNp�"��b�O�)p �S+����t��s��-�����L}��Q;�����],��im�?��ׅ���U�x΂�� +C���C�ve��&���� ��Ƕ�h�5U��fY��K��Z�ģ�9ɽw�,���yaS�#> _�ޒ��H0d�]�+Wx��F��p�ԼE�v@܄x�<-���q�E�1R��+��!w��@�6�`���x]A-�u�ձ�aR����0v���+�㾨Z=���-� 2 7Wޑ��i��Kv���� +K�Q8�b��m1�"���L�"쭆EN�w��ؔZ��E- ��q0�,�L�En+@"�%z|��2�=��w��mNnB����C�Tpzl\vhw�K��푱Z n�L�M�`�6��f��Ӡ@�kO���n�U@�z�.;�w�`7{��I�f��!:%I�ѩ�e�����G��>,������l�>���o9��i�y�a,�P��c��L�Q +�� ����T�dR�����1�95>�,�{��Ԍ�Ea��eq=��ͨH�Xdvm����q���.��+�k7�_�V�Z�V�M9��� +�Ø ��p�K�G��*~?��)VW��(Ϸ�M&���e �S %� +9I��@���(͂w��0��_�S���\�.�}�̖N���:��T�k�0�����!?�צ͚���,$�> �"�cQYҤs�0�)��4���Iҽ{����/&7�"��b�� +N+�t���Q4�FЅ�\8ȄD �:�y.�8� ��[�� b���*�{��Zrpì»u}�8���̑` +��D 7���3�Am$z 0�׊�X�������RJ���GK�Q9�2m FB���!l�B����t��z�P�`����0�����ti9�i]�0R�@gG���>럡#�(*�G*G0��>=����'��l�u: +��T���(�6��ͣ���;�"l��(��d����L.�h'H�=��H,P��e�؊����.�m� � ����޾+��:� +���}����|�V�[r��x�Ĥ���[��!�m�{��c� ��wr���*��^/>;y��1��*�AK�G���-(�]b㤪گL[d<��]��ɫ��\�?fnIV�M�$�t���2��� ��>q�����?к`�?�0R��M�4��=�_�mU��,r8;5-�Y���-��m Ӫ?���Ը����T��c����ne|�w=�o�z�u1��A=NU���I��߷j����?宒�������if,Riթ��C^=���7uԖ��U��\��֧���E܀۳׻��$��C��Umo�6��_q(RH2�xI���c�M������b�6�t6��$ˣ�C��@��%ۉ�/�wϽ=w:��p9f�YL�Y���4H���:t�� �����0�@O�s<��Ը�fiŔ;H�>Y�p!���#8gV��>�8<�1>2r�)��Z8�Z02ܠ6�"0�C����p�Rp�E[paRH �ʻז"CEBM��1'�:#��\ࢴ�����f|���g� T���qp>y҅�2��)�"�fH�e�8����"�(*�ǥ2��X�ܤ_J?�����*W���w�$����(�$# +׷h4 ����T��2���@�ӁќY�s&���:�Rn��3�p���J\ˤu��<�g�.��Xa5b��p��������� ��$q�g|�� g�������[z�O��p#��p�����;d4vV�i������h�,㐴+��q$U8)0Z�q��V�[]]��_wy�$�!��u�_�qa���P�m���w�z/��I3� +Ņ1K�y��/�x��V��SX�,F(��XLs��M���_�ŖA[���Ӛ]aպG���u:�bF�[� �Vs&E�_���xJ��l7笌���g���/Έo�k-�3�ً`J�;6�a3Lb��ݡp8K~i���T��5�fK�Rܴ�ߙ,�%��W��cH �)\������!&κ���VKC�ʑ��"�*�Flm���{�NN?�����{��}|�Z��㓽p��'��5�\Ҵ4���d�e��+��ߝg�[�{�lK��y�`ukv�g�����M5���7�c�ʦE���@���9��յ��F;�]���k���pV8�V(A|�(�W y���R�n�0 ��+ޡ;HZ�6iע� + E�,; (���)�J� �-�>�qS'i�m�"��#}q����ULy6Z�d(?��Y/C�*13�`"�b���2K:�� n|X��W�\�Ďpm��I,�]M_ާ%���TE1�� �ĸ�/��P��RB��;a3��sl?{�T�Ym-�N=����"�����]������U������~|��cR)�JE�&n����HI棯Y�/_,�eN-(� ��;����y�i�bĄ�#�x^�,��9�7\�گ �z=\-������M��,�Nj���_b��O�����Tڻ(\k�|�"Z�zj�Ƭv:�OO;h~���06�}l3[�6Y��R��F���5rP�u�FO�M��8s�Gj.�׏�\S*��N��,>�m���Җ�3'������y�.4��!�8���`���+�����ި�ќd�6/#z�����Pd�>����j)��q�g���u�j�ޙbN�R�jAy�����ı�������8G�b/S����o��6��V�o�6 ~�_��N�w/M�k���C��^zE��L��"y"���d;?��0��K&)~�G2>�P%� zJY�V�"UI<�~0�Nzp��a� �f(� �9L ����׮��^���� ��������f��E�4C�n)��s�\�EI�4 m�Y�z�yn/��y��`���=Z��2��s�(�� JC�+M����Ǜ�& +��!���E9�� <���r��gqI\�"���ܧ��q�8�eU��}A�s����u��m���dkֆ�� +��:{����tNV�\���[G|RP�+�џ�T fh�L�G_���K��Yr�M 'Pz�t�A�A+��qfh舄�]�,��� ��`̡}��¢O�lcq`��U�I8y���7]|6o����S�I��o���B��6���C�L�t���}�0�L 9�����Xi +l���m���}J�T,�3��4Z��v䔐 Y<Ხ�Λ�5��@8Ƶ���e�n:EVI�)�E��@�7�+Lk��p_��tMk��hk��n�j��( ԩ��D 0}8I�n+��,h�y��Y��Y8����-�����fh��U����u���/;l�C�{���œowp6�_z�M�QKBA���W�GIzM+K� ��w�C��;W��ǽe�83ߙ3gf��g8�� +��������z85���/^* ��T���ˑ� zb��ȻW �%2�.Z1�y���W����� +E}�>e�>�:�p45�_/��H�@sx�[�!rUӢ$c^�����Ȳ(:[��q{Ŷ�eQXoD`���^X6$� �hjd�6yl1��e�����`}0 �v^+��`��g����' Ml> �v6Q�NG�q�|��u��p}7@p{�� o�|4���9�q�ʨx<'LG������?�ĩ&���� /(V�) +i�ӵ'�Ʌ��B(�p9��!�[�mS�n�0 }�Wp@��ARc�M��k,@�K �@��t-L��NZ���A���d���9<��7�j�1̠o���^�]�����p��Sn!��[���R~�s +č��~�����ѐ�Kf$n��<���x`�8��s4pi��F����d ��d�!'el�p� P���B@�twh�#���D��WrZ �G����~ws�s�*�Q�N�B�m� c8qJ��x�r!D*�%��dZ�"�����z.&���"�2�G��.�rb��"\!�\���fŧ{i�y�`��o��hh�%��W,F<�3�da���s���'#Sӆ!��R��Xy}p�dT��G��$E�{��M�o����iT���`4�Q]�ޮ_k�:?A���m��DJZ2yD~p�ͧȢ�7�h��s��-�#�R���Z*�"�lt�̭�r�p,�W=ؚ24��� hG��شAA)���ڬ�������G��\tw�3 +���e�q��7n��|| �\s�K�hS&���;�����5*+Y�A����Aʍ��.[���K�Ʉ[�~b¬�0K���C�2s�UhP+�I�����f% �����As z��y��ÆR�Nj��� ���"�Ν +N:75� 8*�w�ܘ��d8�N&ʟm����Wh5B��3�b5�"M�n�?�c�O,ז�����|z��R]o�0 |�����/�^��KWdX�a(�f/�(2 S$���E�� �n�~`z�������'W;(QjA�y&%y�;���c>NF�p_+��ʃ�`+��U��Zču;R�!�9\�A������&� NW���ī���0�L|_��ڡu#�)AZäV�-�N��%�� +Z�|T�h�$��Lei#XYS��(�E��1��Vx(�?ha [�5pl��@Aڲoy��A�D����_m"�$ >�22*�2KA$v�Ӳw� W��i�V�5�� ��Jt5N���0?�?$���� �F�:Z�eG��p�7NN� �/p�tsa��|2�\Jk������f��|��p�{}vHC�l ���u�k�V#��x2Eȁ̱����#S��-���(i^��8����# UA��ߒ���g�jACe�ҵ�:��/-V�����S��k�[0�}s��|<�"f��������ݺ:�[�A;����,-�FN��&���'��T�o�6����P��d�q�Վ]gY�h�ـY0��"F�����%[��-k1~�Eݏ�����W8�PjA��'%���:���t� ��B1�J#('ȃ��K���<�*�ʺ-�U�!�)\�A�A ��g�dp��<�g8�-> +�J� K$���b� +��i � L�O����n���@�K�Ah�$FP&��^Y3�Q0“�M��������u(U�� ��]/�`�|>�g[�D�6k(�##��NH�/�����J�i�p:;R�����ǟ?_k\���(�Z0�mU�?)��W0 `�$~[�e�6W��ԓ�g;0�M�&���A����=��[:��ץ�G�����>4i��ۤ5�p΂ �y�-�z�B����/�n:���Jt�?�[���,-]j%8 �W��L��tRWm���D���̚Y$�x�¬&�t��J�޼�7��=�����m<�[��o=)�J�tz�r��r��H�Ѽ’� ����Q9$���F���f3xז>�JD0�9�c��xc�Pr[� rKP���|�X���+Q����b�\j���R���X��9x�?�f�N�/��N޵�F�K2-�I���h�B���J��k�‡ �aϕ����P�W�}��uJ�q��3���x�˖����Y������� �h=Yڹ�f�R�o�X��.kub�i{�KY@æ^���4��Q�S'���7�/�5:���A���_�`�ы����ob�0~y���~�ݿj鐓t�Hl��_����� +Y@��bt6/N!,�����v��[ ��}����*� 5��j4�=G���N1���)R~�zK +��FmJ(�AZ9��] c[�lB��%��j���љ9ߙ�w�CFR O��^INy�(��uI�����R�JT��as\�jI���̺�WE�h�N�!|��ܑ瀡��N�����0�����'��c� '�td��(�0�5�բb�Ccxa=�$�֐���J� er��+k�4�@X*Z�}_&g��|G������Tx� +�%8��� m���qO� I�*����z#�$�¦t�4�ׁ���\y�l�z�$R��Q��Jx��n�e ��d��?p�B+�ߦ���ߧ��x6�\N1B�2wƮLk���~������'��#�Z +&��we���g o����'����+#�v��5��$��Y��i��ۏ;<<.c�X����� +�&w�s��e���n6T��j�m��SO�����&���L� \ ʾ�5��?E���U�up�zfw�Q���V} S���=m��/����˛��`L[��XA��Y�l���l^bώ�b��|n�} I��Z˷�ǐHeL/y��2�TC��]U��Z��S�Ί��,�D!!����r�����y��4B�/����7�+���X�#L��x�A����1w݉J'�}s;Y�|c��a��1�g�'Ú�MW�f��w�jz�a(˳l Ͱ4̲���/_Y�q��+�N�y��U�բ��=���a-q�0�I�TQ"���J&��{��� +�uE�W�H���X/���q+ +�����h��< |4��a-ZR;h�����<E�AO1�����@<��"DcH�hb��m,mәe1��nv<��{���mv�@���[}���r}5����`��� /�T����#O z�2���ߝb`��+�q(~pQ��J����CjcHTq���'�Xɿ_����T�n�0��+�� I�}ܚ8u�m�>�:�M�%"4)�+�F�/(ˎ�8@y���;��%/ߗE�����NI^�$?y�^D�~�>� �R��#���Hv���x���L&�keb�Gl*��qF�������F��T�O�0�����H�Ĥ}Y)�m�M�|ۦ��\׶�NK5�ON���I˗$��{��}��2 +�b�Y +���%�?Mz�I'���A.�t`�=�� +���*�gcW,g��X$pɚ��B�@��!k��6���waBSt^���TÙk.la�XE�3F{���vu�+�� ��T +Ħz@+)H;�s�s���.XE���վo�σ�dRU�|��� �n]�2XJ_��)Y�5�O"�sr�]�<4?�����t������(�4�����I:�G׽6`0ߎ���h���k@f\��J�Q:�Zaz��d�Z�.����9�ӌ�� UD��)1�{4���1� T2��Y9'���l�ы"��9�qFA��;8�t�b� a�z&�-�z�C�e/�GV<�-��l���Ё ���&}�WG6_�Y�W;�qu�r����!M+Ÿ>���Vx�Gޞ3.�_ل�݆���U�.x.� �O�u_�JR� ��!n�'p��]��Zx*ڠi�*�vޠr�t���I�e����A㻸���GG�rA����r���*+H�M0> Oى+�5��Z���h�ŖB����v�����2N>4�l�0������JtW� �֞~-� m=w�\>R�9�,�ﯶ���&UC��p4{'��̥�o�7��A�J%`j���z�t���&�&���u_)�:8|�U�*��ڷ_��u�̵3����^�i�oC!����?_���0*�ͺV8��ZO�uR[o�0~ϯ8�*� (��(F�V�Z+@ڥ�qN�Uc[�C+��CHsi����v�/�T� BʉF�Xͨ]ڽB3���^ۃ6,f f�PD[�1<$l��d���� > `��WN�3jk��h�����<�a�"�2"����Ҝ +#�(���k""�RX�V����7R�M�s����挢0L�Ro�eRt@q$a�p���n'���ʂلX�3G-�`�lօ72������ �A�ExH���a6��祦(�0�󽱸 ��Fj���� &�p�+���=�rb ,�^�-Pw�+5��z�6��D�D����WV�m�E8�Y��U�3���HU����_S��7��M��B� +�ʰ\R)��)�~������,t +ђJ���}gn9���T��[�Zc��5�3י ق�וŘ��6�l��΀[�Dn6DD9b��bvj�f���޻�\��= ?��Oi:,���;L�9���͈ZAy�YzEl��6�k�ut����#x�x��`׷��dq?���OƳ��~//�4��bi�^���������O/ ��)xe���JC���t�F�jwo8��J��1�U�O����L�K��i�x�`-1�]}Oٰ۪���3���w]|�i!%7 ��;x��Z_o9��� <�u��8 �ݤi�]�5W\�{�A ����Ҭ�Ij���$�iFc�m�pF��E��#%���"+ �$'#�MԽ�(�/���d'�{F%�h�@%D(�+���|>Cqɋ���LA��p!›����P^��|Y�~��b7�$RQ��,Q�+Y�Y���Qa)$�)A���BV��T��*��fwM���D�l�ņ(����Dx��h����˫�+��(�2���HH��{a +�Te���"AHxZ�<1�AY��CFį�����hTJ-K��@� ����?K<�l��Θ�~��^�L��=S�@�Q��h�/��&�"��K+�-�9MZ���s�J���jG�헉#��u\��?G�� � ̛�Ն��[<] �����T*����?�g]v� +͵��&�V����n�����ScoW�����N-��X�4���3_ �f���W}�H��gFcM?1�.$� UEa4�N3����b��l0�Y�`��[]�Z��n��l}Ӝ'�0�k�N��!V����>�h��n2��"���� �V�������}{w�� ?��Xf���9��@�^f4O��O�x.]A-VF� ]3�J��([�0��n0��&;�" �+c�OW�U+�w�2vX����Y�e�邤i�Iô�5��ȵ�@U + M�F})��� �6�h�Ƒ�N�+�i���^�5?�+�a{6;9�3'p^A6 ��ÑF�j���L��u{W�΂@�F��dd�ħ6U�(�Ŗ0��;�LV\ I2�:��g�bU�8�f�.N5��s���ٱ|v�������u���vM2w ������ &�S���@=찕�,�}��$kt2���Aa| +���)�R�T���L��PO�κp"��L�s+C6�_j��sg��\�4~R���Eߚ=�ύ�vϊH�B���EA2e��2�K���:� 6�eӅ� � +xj��1J����C�fmA����-^�� n���d��?TQ�B(�/v���L��$벱)V��5�tT��Y`BWS0��o U�+^�t���j'-4&܏��5�� ��E."N��%UJ� B{�Ζr���]��ռm�0�p>*W��u�a_ٝR�J�5H�G��� G�U��6�|{�n�vO�� ����ٕ�"�1[����@��ߘ�z�v� )�^�@h�WV|[� +{W�MaЋ~��.,�w�)�E:6,����0OF��<�[��?���̏��F�M��<]���*��L+_u���J���s��[e;�u�.?}0�"G��n��W-G��p9����cE���y>l_�����M������T�Z�C���{"ϭO���m Ñ���'оkw��0�5_�Րn�d4TM@'�xg�;���@O0O.�` ��o�?��;�l�q�S"C���8���<�T�͛���&i����q8�H�*u�(�[��A�'��P��޽O�R�;X����]^�����u�n��_v2m��i�`$T�4Un����)�T m��\�p� ��E��[*zoZv�ƒ���v��\:�7" �eD�f��-B�Z�\�KPE�9P��&���%a���(�B[�*���;������Z- Т��{����)s�G�vW*k��m��1�x�:��J\�{5�v� ��;KM�8B� T���: vGS ���д�xt����|n +�� ,������{�|+��k�$�L�q�S}���1�J�C�r��}�s�k'�:p���y��Ϡ��|�%I�ܵ>�Ѯ��ʅ���m�wS�(���$�������~����! ?��KJ��o �ϳ������vf��BS*Ѣ�}�q�Eo���L��F��D��[ �v.햬����f�n�6�+�#��j�^; ��[�]:(��e�+��t: �3�0^x7�'�9�*�W4W2�����~ E�&GL���{�� &��y}��5;k͒�*������z��V5r�9u�����&;ht��ě�-�a�$I�r��L���,�io��5) +�e�xUARk��� O3�, +]*��1mt�2����?_�qŌ��I�iо�5`����K��Ÿ��C`�U���B���'���T�c�M�I���������&<��Qx�F���pj�ٵG6p��`B"(��?�aOU O�.��!9�@Wb��7j�6z5�>`@� �x V�����u��t���o�F�� +}@bA��{�k� �Jhx� &�)�mb�����@ͤvr��!�a��)��ݫS%Q;�������}�) +��+<�}_oO�U�D0���H�� #8)N�}xg2��DM�Q���a�z4�r#� Ȝ���;��u>.���^��.�qs�%*�A S�,u�Z¯`���<�Xg6���lI�:eu�ֶ#��'�w����R%Ϡۭ4�1e��گ2�_�lftkB:~C�Y�0m��u��$��� Pu�`N�iD�xދ�a}5z]�!.�^C��%_������j����bz�+��L�u�v�����A.#f�]��*�5� ��`ɤ�� +����sc��6�#�}�:�s"�>� U�g���5�����_Iˌ��_���Hd(���&�Y٘���Vmo"7�ί��PwA4�:�jC8r�)j)I>T���Zgl�á*�����H��������3_�Lj A.��ؑ�f�5�?w�~�]xH����a�@/`��5�� C\i��b�ļ��B�]2�-9�`V���>K�S�q� �`�-\�r�Ҥ����T\+�b�I[W8��(EXx)����Cj�튑ЪF"sk��l������ׁ*K�RF�a�r_��FP +�w�[��uR��o)�BgG�����2E��wwz)��7�&�dk\+G0Of=^O��Mo�>���/�q�P`ֲ��+ng�M8r5�9 �k�\{E������^�d���nkfìÙ����7��ב}u������V���g��+TT˿��FH��:�U�3O��%s��[�n.��f�e<,+֌�ފA�]�T;*��n��\��bo՞�->{a1#Kк��Rpp�H�t�=Z�����9̵.��R���� :���|a���A��� �c"�^š�PQ.�=�����fY�[�i��[�k� CP^��!a_�:���\��V�(�ڡC������.N:�=87�r�b&A\��%r<�FO0A57z+��aQt5{Y^�^� ��Sʫ��wzcԫ�t`tH�A���~� �Z����n�rO+�����y�D��)|1WBOr�ao2���i\��;��w�i� ��t��q�*enz�u|��>���6~��N�Dz�M�]�b��X"�Ww .7�nvָ^���n����ԝ� ��{&]�)��V-�J�!r`�����{Z-�ϛew�TL)�$������ޫ�v�%��2l�ϕ�&Җ%�e��Uz;}dbL+���r��cl (�Z�c�2����MoA ���+|@JR�-\�Z�*q!Mf��#&���$���w4��JQ)�͞�~絧oc�D� �P���_��(�7�Iq~R� |k�@�<���B����Y-�qǮn�vWLA��*05Lx����c�Õu��#&d�JW��M�=f �`)�U��r|�A���`{�L{g��Qxm�C�ha�p��}�Y\��ΣZc���(�쵰���4����"�Pv�� 2k�h,�mc�&,ۍL�"�qi��n� ��E �{���Fd��C�^�J�c +��V�Y��l �$�(ߍO��Q �B̏� X���951u�0��`Є5&-�X�S�X�Q��FR>?8��t^�~md8j��u�p� +����5��;J�������h�%��5�' +[�y���J�� 9dq�m6�Ce����i��A�=�䥿�P8�jF�A������c��\mo�6��_��� +I��@/w���״1v�4��`�Ҭ�5WTI�/8���"��%%��J3|�/Ù!�����5��<�W�KZWEꒈR�U5�2褰� HV�QD(-S;*3*3Rg�U��QPf[� {��<��ʠ��lؕVb��W**����,˶m](�맏 F�|�����RE�� +@f���e��^N��Ӄ��ߠ4�<<I�ߓfG嗗͎���%��J�B �����r��[O���Ȟ��--@�����+��J��X;�wͮy�7�.F�J_*����€��8I,u�v����vD@��{��V�V�'jE �w��S�1� �}�1h[�w�%�~���랡k�G���(.� ��h�#������I]��� ���#�b�� +��I�z D�@�RI�)vpM��K�J��Zq,�������N��܏��Ģ3zyYp���%g�[մjҍ���|e�WV����#��ɴr4�� +��=�����]8����!�&f��UL�2�Fko�۹kڳݲq�'�㘂�\3XB����� +�=O����ن4I-h�!|�S+Ox��N�� �;��š�R��d nI��xX�}o���A�4�O0N�{<vb�Lgu�I�U�u �X��x���4 +��� �L�?��!�^SF�C`��E4�A9m�}å�L��ʉ�hn<7��Љ{l�T=F���(���44�s(#�J��4��ҤT�B�����q�,(g9V����K����cp7l:'����~�V0��� +�@�T��k�������� �[��Ǝ� =GJ��� � +(�Z*�R��(D���%-SS����gH��~;�'@��� +(T+�bb��h^�LF������-� ���=q��>���������F�w��x��=�F��r= �����~k��p� ������/���b��L��z����tE{\��n���@��<��L}^�e��2}�Q�D�Z��j D��TJZG�5���V[:��٧�t���u +��WJB��9�����Dgg�{�!���B@�\� j20�@����@ʫH����BRUm�fB~����~Jc;uE�#��-yT��|�5ϵ�{3�d��O)��WT��k@.��F�D�ș��2}xڻ0��QF�p�q�������#�u�H�[0���_f.旣N����U��n� �iݞ�b���ñ����4jS�h+|L1����=Ա�}ÅZ~�3��������w �n�1I�p��t���2B�c���.� �A!� X�D,>�5��L���\D��{з���E̻�tVA~�3��k��؍��#M5�b]*0�z@�p��+R�t�֛����N��J�Pk#�D�vj mS �F �.@6z=1��v�ĥ�젱�Jk�c��Ʀ�e���5`������1�?a�'@M�>�i�E�%W�7�~ĄI����,�Y'G$��ܚ��ť�i�@ԄEF_gN=% +��-a��3_��0�z�ķ�)z��Ƚ:��{t���OX�?$�K���ߒ�'D�H�E'4��\p�~_�w�F�(g�BK�7B�o +(����7+W&Ͳ3*Cyx-�?R�����(��uf�����cK�L٫iX��©�5 }D�h��bD��t�k�%oER���y��s*�ec/t���#��JV�P6��\�F��A+�N��N�ۉp�y ��O���i�n��M��n�Sl_r�D��X��sL� �<=.g����g����'�iּ�US]Ӛ��-o�������[S�.�gT�L*���JGue`pwb�U��� ��o`{�cz��6$���5!>� ���B_z�b�0��X�2�z��h�sf�ˠ'�lz1���+?�:N��W���(/\ ]��W=ER�t����Ep�~�1Y�s����e��khx��k/#�BK�v s�J��b��TV�׋:��N4���ظ�[_mS�.�w������X㻴x��h�$�.cܥSWc +���F�?�P����-���o�kF�8�R:�?7�_ z�t`㣃F��C��ba��̄ي*vY~����d��ƌ@1cH�M��;L�& +>jY,0 �Uc�V��)8cP��:�U���^�X�ۭ��X���Ao�N4�+H��M�oJ��@�G,�$H4�-�M��� +n3��j�9DG���ɇ��H:����,��`�w� ���`.:��rH��p�� qN��7�_�y�=8�;ٯ����� !�'7�|����hh M��#��7|L=�L,F?�$��TC������k����!h]�$����SL:K!�m��@�<(��'���y�Z$w$��� �#�#/_�8���Տ8���a���~�!�z�r�Ջ����g��� ��hhQ������@MqQ�ɢ{��c��C�wҬ{��H�XTt�e�\�=�q&�˶y�����[b�D+�b�4t�U>[%t������Ղ�CyV6ϑ,/!8�������Q%\��;k����1��p���X�8�9��"����m�eK:�-��cl�-z�*gvY����f�e=̭��HG)��̽9ۻ8��s�ȹ����ÅDeZ "rC����rx~!v���B�>̩��������ο�m���Ѻ�w2ʀ�nu�ܑ,pǐb���f�����;\1Bxv�8�_���E��Τ���w �/M�?$I��N�?����Ϧߒԩ * ��:9[_]e�e#�)�_���h�����g?>���.��ko��������뇢�:vN��5�7���<��<;3�4vm�{!�K/�h���E�%��(��H��/�uA����DH�y-���?LO������� �d)&HA�$��\����q�[�VkI&ɔ���7)�n�KA^P������hgd7THF3�J��h��uy��B$4[�$�$g7�̹�|�s"�@�e���]]a�,�La�2�*Y��"*��1��t�?�������JoL��$�T��Z� �L��T�y� I�h�|��� ��&@.ה̿i����BafB����_�'�,�D�BV ��E�)/�����{�Ȝo D�o �/�˳��s� �,��� �'{{IJ� �\��#�����ɫ;�IV���K���ْ��6�x���@�%���^�R�^ڣ���.�yʾ]�?J�#�<�ֻ��<�@��A7��I���*��E����(oR�t깾ֺ�e"'&� ��%�f��T�=�E��n��2�#��V\�9�;��Y˳���=7z�J|6$,Bgh����gxv�5ꉗ��R�S�3̩�o1� V.db+��P>j��f���tzP�D��G1�x �Z,��+(r����̄4$�3�P�|�W��%���"�{���.ԉ�YQ߁���e�x�����`w�����ȷ����Z�ң��W��z~ۤ�j�B�OL��gk*����*�oh�����J�� ś�����oLIE@G�h��4r����~t�� I�T�q��j"CT6$,,���=^ ��"�=bJ��o�#~|󋖾���=��_��� W۵�,*�yz�M�R���n�? g��H�3.d�̲�\r*a��q W�#�9�z3�}���}kz�TQ��{����4l*O�5?��]M�]=������Y�a ��r�� &S�D��̈{�a�3����*��t=���΃�� aC�ƈTp�j���^�|e�h�;�+��QB�xn��M� ����:�Ns�_j����Z���ל߲l�N{+6�-�>H�l�>f��l���@�����>h.�,��Z�$��h���o� ��n��Ӊ���Q�!]�n��uy�=̿�ﳴ�o1�/�\�7�SFEc�;g$1����r�c�J@ C�(,[��; �@h ��c���/^�O[�?'U5�<$6$�E� +�f����4��}P��E���L�ӆ�E�P!ܸ�Y�k���K�^,�|Ɲh-���^}�[�4u� +� Ylh�D��c�b���)�hd�a��!�GU�zʕU�Ƌ��|xԤ�8uӑ_y�juD�Z[�e pB�O̕5tuX �B��^���[9҈��ɯl%�Hև��Mn sL~Tͤ�"]�A�!��C<�� ̈ 3�P�w��[��>HY���7�Q3�e�� +�i��74����b.3#���� ��pP�h_�{|���e�s� [�T��=�.庳��/�f ��y<6e�!6؃"��m�*��%jQu +��U�dIS��b-e!f��Ś�#��R��xn�Oɿ�壳�~�ݶ� P�n��%�I��w^�i ��lkF�n�μؒL�IOO�.b����Q� y��?�]3�(�R/T�}̪���&�M��ž7֛�z7�@ 0]O��:�o8^ d2mx�|�X�f�'���H^=D��ncn�1�M�S�`2����`t�}�&0&��K��8#�0��,���&��B����� ]�6 �ekRi^F��p������ΌX-YAݶX��h���2�������U�j�5H�� +6u���ۧ�^��P=u=�y�߭���"j蛂Jv�R&���9k�iDŽ:",�C^�״f����c��((3�90��50�iU}0��zp��T �1l�\�4�ި[ׅbw�G���� �8�V�̌��H�_hìX�� +L{����|�m�Vl���#��YY��l�QYr��ْ����5$��� :#�A'� !͈D�Txg��?�t3�E�)UC��:��7@N�P������'6�r&����;RL~���?[�)7,�� �(�^R��:I4���LZxSwU�(��p�*͟�i�VS�3�}�uh`c��*>�6�Mi�l?n���^�6E���*�٩�iL����!W��g�!��tQ��V�T �WA`��eO��#x�b��&�}��q��sl��j�h�o]8�t��:��ߚ���^gPz�M�a��e�{�"AOo��h���0��7�����Y7��˧�W�y�o��}�15c�0#����,�y��Xƴ�< F� +�@���Žv�������z��,��$�ѭ���b��;s�\�Ɯ��C:T��&�]���7��OO�@����&=�Ѱ5E 4��P0�6�#]��nv�����j�1�f2/�y���%l�:�gW�K�Qп�t��q�L ^�c��f�t���y:�`��L�|��0�$A��+��EH�:����(P�lH�EO%���0\&�y:����0���$ �N' +��� +��T���{�nz=S�� +�;�X���h���#�K�mS���J;���_5�n�k�`��\��bPX*Iy��qv�/u� +K�SЋ�`i�����9@' +�#��&�b�e)����-9ӆ8rX�?��n~�O ?=��hf֯f[��M:�dq=��'���o��x�ƀВ�=�G+���4�6�~��(x�T=o�0��+�5�t)��dj�!)��L�%"")ߑ����2�Xr�t#�������5��m�Z^-WR�7�������÷�v���`S�ѻ�sѳ�u�m�T�u���2P��W�+���ϧ*6��LJ@������.Ac�K)"P��r ��\(��@K�X�Q1�� � !��GA����G���6�?����84w �9�r;����L~�/s��^�(��:�W�Cybj��z�2_�1�ݤ�#�!,�G K�Z�2{�d}5�?s��H�Za��ǻ��KxZ`���e"_9cb��п�'1�? |eSl3,��]~^a�0�/6��d�v�'����Zn����6�E � �1�����cK[!�ɜ����c,�ž0���;sHM��W�OK�*�(PPRV�p �w��q�s�uUVVRP���S�N�@��+��|K�V�z�BP +���B@�RilO�-�kw��K��� $@A�O����{oތ� �N�9��$�#8� ƟF�����.��y~6;�]L��y7?��l9��lv� lY++� ��;�E��uk2dQ�����w��f6���@�N�YF��`��jC��h㎢Z�u�Ӵ��&���MvS=�w�>{D��ߏ*Za�e�T�-9@���b�p��� V��u��d#��2khH*e�O�N�~�=wP���F�&��`���WV�R)l�!��P,��4d*�@����JjP� �m�%��ZC� E�c#H'�J2�f�Y~��'�p5ͧ��U�/?�e� ++j=S��s����r~ul��*��:մ����F�:����Ž�������u ���C;M�!�NB��h�XUtBCp^ m� ���B�[��~^A��Ԛ��nz`�{��mg�D�3��5��������s�6�+�-�vYҽG#�dĢ+��p?��#Ԏ��h�vq -+#>a€�i~�?�s�<���]Qk�7��Zj�)�Jn +eЇ��:�'��$]�¬����M�G��P�G��v�;���/��/�(��*J-)-�S��RPPPP�N�,��/H�+H/��/JW�A�����&�敔�%���p�Zs +g��40���&�6cӮ�k`����.��^v��nc����h��??�߈0 �2rݛ�DCʋGBMB \ No newline at end of file diff --git a/tools/php-cs-fixer b/tools/php-cs-fixer new file mode 100755 index 00000000000..2b71338c1b3 Binary files /dev/null and b/tools/php-cs-fixer differ diff --git a/tools/php-scoper b/tools/php-scoper new file mode 100755 index 00000000000..14b18a08bdf Binary files /dev/null and b/tools/php-scoper differ diff --git a/tools/phpab b/tools/phpab new file mode 100755 index 00000000000..affabecaa81 --- /dev/null +++ b/tools/phpab @@ -0,0 +1,987 @@ +#!/usr/bin/env php + '/vendor/zetacomponents/base/src/base.php', + 'ezcbaseconfigurationinitializer' => '/vendor/zetacomponents/base/src/interfaces/configuration_initializer.php', + 'ezcbasedoubleclassrepositoryprefixexception' => '/vendor/zetacomponents/base/src/exceptions/double_class_repository_prefix.php', + 'ezcbaseexception' => '/vendor/zetacomponents/base/src/exceptions/exception.php', + 'ezcbaseexportable' => '/vendor/zetacomponents/base/src/interfaces/exportable.php', + 'ezcbaseextensionnotfoundexception' => '/vendor/zetacomponents/base/src/exceptions/extension_not_found.php', + 'ezcbasefeatures' => '/vendor/zetacomponents/base/src/features.php', + 'ezcbasefile' => '/vendor/zetacomponents/base/src/file.php', + 'ezcbasefileexception' => '/vendor/zetacomponents/base/src/exceptions/file_exception.php', + 'ezcbasefilefindcontext' => '/vendor/zetacomponents/base/src/structs/file_find_context.php', + 'ezcbasefileioexception' => '/vendor/zetacomponents/base/src/exceptions/file_io.php', + 'ezcbasefilenotfoundexception' => '/vendor/zetacomponents/base/src/exceptions/file_not_found.php', + 'ezcbasefilepermissionexception' => '/vendor/zetacomponents/base/src/exceptions/file_permission.php', + 'ezcbasefunctionalitynotsupportedexception' => '/vendor/zetacomponents/base/src/exceptions/functionality_not_supported.php', + 'ezcbaseinit' => '/vendor/zetacomponents/base/src/init.php', + 'ezcbaseinitcallbackconfiguredexception' => '/vendor/zetacomponents/base/src/exceptions/init_callback_configured.php', + 'ezcbaseinitinvalidcallbackclassexception' => '/vendor/zetacomponents/base/src/exceptions/invalid_callback_class.php', + 'ezcbaseinvalidparentclassexception' => '/vendor/zetacomponents/base/src/exceptions/invalid_parent_class.php', + 'ezcbasemetadata' => '/vendor/zetacomponents/base/src/metadata.php', + 'ezcbasemetadatapearreader' => '/vendor/zetacomponents/base/src/metadata/pear.php', + 'ezcbasemetadatatarballreader' => '/vendor/zetacomponents/base/src/metadata/tarball.php', + 'ezcbaseoptions' => '/vendor/zetacomponents/base/src/options.php', + 'ezcbasepersistable' => '/vendor/zetacomponents/base/src/interfaces/persistable.php', + 'ezcbasepropertynotfoundexception' => '/vendor/zetacomponents/base/src/exceptions/property_not_found.php', + 'ezcbasepropertypermissionexception' => '/vendor/zetacomponents/base/src/exceptions/property_permission.php', + 'ezcbaserepositorydirectory' => '/vendor/zetacomponents/base/src/structs/repository_directory.php', + 'ezcbasesettingnotfoundexception' => '/vendor/zetacomponents/base/src/exceptions/setting_not_found.php', + 'ezcbasesettingvalueexception' => '/vendor/zetacomponents/base/src/exceptions/setting_value.php', + 'ezcbasestruct' => '/vendor/zetacomponents/base/src/struct.php', + 'ezcbasevalueexception' => '/vendor/zetacomponents/base/src/exceptions/value.php', + 'ezcbasewhateverexception' => '/vendor/zetacomponents/base/src/exceptions/whatever.php', + 'ezcconsoleargument' => '/vendor/zetacomponents/console-tools/src/input/argument.php', + 'ezcconsoleargumentalreadyregisteredexception' => '/vendor/zetacomponents/console-tools/src/exceptions/argument_already_registered.php', + 'ezcconsoleargumentexception' => '/vendor/zetacomponents/console-tools/src/exceptions/argument.php', + 'ezcconsoleargumentmandatoryviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/argument_mandatory_violation.php', + 'ezcconsolearguments' => '/vendor/zetacomponents/console-tools/src/input/arguments.php', + 'ezcconsoleargumenttypeviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/argument_type_violation.php', + 'ezcconsoledialog' => '/vendor/zetacomponents/console-tools/src/interfaces/dialog.php', + 'ezcconsoledialogabortexception' => '/vendor/zetacomponents/console-tools/src/exceptions/dialog_abort.php', + 'ezcconsoledialogoptions' => '/vendor/zetacomponents/console-tools/src/options/dialog.php', + 'ezcconsoledialogvalidator' => '/vendor/zetacomponents/console-tools/src/interfaces/dialog_validator.php', + 'ezcconsoledialogviewer' => '/vendor/zetacomponents/console-tools/src/dialog_viewer.php', + 'ezcconsoleexception' => '/vendor/zetacomponents/console-tools/src/exceptions/exception.php', + 'ezcconsoleinput' => '/vendor/zetacomponents/console-tools/src/input.php', + 'ezcconsoleinputhelpgenerator' => '/vendor/zetacomponents/console-tools/src/interfaces/input_help_generator.php', + 'ezcconsoleinputstandardhelpgenerator' => '/vendor/zetacomponents/console-tools/src/input/help_generators/standard.php', + 'ezcconsoleinputvalidator' => '/vendor/zetacomponents/console-tools/src/interfaces/input_validator.php', + 'ezcconsoleinvalidoptionnameexception' => '/vendor/zetacomponents/console-tools/src/exceptions/invalid_option_name.php', + 'ezcconsoleinvalidoutputtargetexception' => '/vendor/zetacomponents/console-tools/src/exceptions/invalid_output_target.php', + 'ezcconsolemenudialog' => '/vendor/zetacomponents/console-tools/src/dialog/menu_dialog.php', + 'ezcconsolemenudialogdefaultvalidator' => '/vendor/zetacomponents/console-tools/src/dialog/validators/menu_dialog_default.php', + 'ezcconsolemenudialogoptions' => '/vendor/zetacomponents/console-tools/src/options/menu_dialog.php', + 'ezcconsolemenudialogvalidator' => '/vendor/zetacomponents/console-tools/src/interfaces/menu_dialog_validator.php', + 'ezcconsolenopositionstoredexception' => '/vendor/zetacomponents/console-tools/src/exceptions/no_position_stored.php', + 'ezcconsolenovaliddialogresultexception' => '/vendor/zetacomponents/console-tools/src/exceptions/no_valid_dialog_result.php', + 'ezcconsoleoption' => '/vendor/zetacomponents/console-tools/src/input/option.php', + 'ezcconsoleoptionalreadyregisteredexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_already_registered.php', + 'ezcconsoleoptionargumentsviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_arguments_violation.php', + 'ezcconsoleoptiondependencyviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_dependency_violation.php', + 'ezcconsoleoptionexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option.php', + 'ezcconsoleoptionexclusionviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_exclusion_violation.php', + 'ezcconsoleoptionmandatoryviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_mandatory_violation.php', + 'ezcconsoleoptionmissingvalueexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_missing_value.php', + 'ezcconsoleoptionnoaliasexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_no_alias.php', + 'ezcconsoleoptionnotexistsexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_not_exists.php', + 'ezcconsoleoptionrule' => '/vendor/zetacomponents/console-tools/src/structs/option_rule.php', + 'ezcconsoleoptionstringnotwellformedexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_string_not_wellformed.php', + 'ezcconsoleoptiontoomanyvaluesexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_too_many_values.php', + 'ezcconsoleoptiontypeviolationexception' => '/vendor/zetacomponents/console-tools/src/exceptions/option_type_violation.php', + 'ezcconsoleoutput' => '/vendor/zetacomponents/console-tools/src/output.php', + 'ezcconsoleoutputformat' => '/vendor/zetacomponents/console-tools/src/structs/output_format.php', + 'ezcconsoleoutputformats' => '/vendor/zetacomponents/console-tools/src/structs/output_formats.php', + 'ezcconsoleoutputoptions' => '/vendor/zetacomponents/console-tools/src/options/output.php', + 'ezcconsoleprogressbar' => '/vendor/zetacomponents/console-tools/src/progressbar.php', + 'ezcconsoleprogressbaroptions' => '/vendor/zetacomponents/console-tools/src/options/progressbar.php', + 'ezcconsoleprogressmonitor' => '/vendor/zetacomponents/console-tools/src/progressmonitor.php', + 'ezcconsoleprogressmonitoroptions' => '/vendor/zetacomponents/console-tools/src/options/progressmonitor.php', + 'ezcconsolequestiondialog' => '/vendor/zetacomponents/console-tools/src/dialog/question_dialog.php', + 'ezcconsolequestiondialogcollectionvalidator' => '/vendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_collection.php', + 'ezcconsolequestiondialogmappingvalidator' => '/vendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_mapping.php', + 'ezcconsolequestiondialogoptions' => '/vendor/zetacomponents/console-tools/src/options/question_dialog.php', + 'ezcconsolequestiondialogregexvalidator' => '/vendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_regex.php', + 'ezcconsolequestiondialogtypevalidator' => '/vendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_type.php', + 'ezcconsolequestiondialogvalidator' => '/vendor/zetacomponents/console-tools/src/interfaces/question_dialog_validator.php', + 'ezcconsolestandardinputvalidator' => '/vendor/zetacomponents/console-tools/src/input/validators/standard.php', + 'ezcconsolestatusbar' => '/vendor/zetacomponents/console-tools/src/statusbar.php', + 'ezcconsolestatusbaroptions' => '/vendor/zetacomponents/console-tools/src/options/statusbar.php', + 'ezcconsolestringtool' => '/vendor/zetacomponents/console-tools/src/tools/string.php', + 'ezcconsoletable' => '/vendor/zetacomponents/console-tools/src/table.php', + 'ezcconsoletablecell' => '/vendor/zetacomponents/console-tools/src/table/cell.php', + 'ezcconsoletableoptions' => '/vendor/zetacomponents/console-tools/src/options/table.php', + 'ezcconsoletablerow' => '/vendor/zetacomponents/console-tools/src/table/row.php', + 'ezcconsoletoomanyargumentsexception' => '/vendor/zetacomponents/console-tools/src/exceptions/argument_too_many.php', + 'theseer\\autoload\\application' => '/phpab/Application.php', + 'theseer\\autoload\\applicationexception' => '/phpab/Application.php', + 'theseer\\autoload\\autoloadbuilderexception' => '/phpab/AutoloadRenderer.php', + 'theseer\\autoload\\autoloadrenderer' => '/phpab/AutoloadRenderer.php', + 'theseer\\autoload\\cache' => '/phpab/Cache.php', + 'theseer\\autoload\\cacheentry' => '/phpab/CacheEntry.php', + 'theseer\\autoload\\cacheexception' => '/phpab/Cache.php', + 'theseer\\autoload\\cachewarminglistrenderer' => '/phpab/CacheWarmingListRenderer.php', + 'theseer\\autoload\\cachingparser' => '/phpab/CachingParser.php', + 'theseer\\autoload\\classdependencysorter' => '/phpab/DependencySorter.php', + 'theseer\\autoload\\classdependencysorterexception' => '/phpab/DependencySorter.php', + 'theseer\\autoload\\cli' => '/phpab/CLI.php', + 'theseer\\autoload\\clienvironmentexception' => '/phpab/CLI.php', + 'theseer\\autoload\\collector' => '/phpab/Collector.php', + 'theseer\\autoload\\collectorexception' => '/phpab/Collector.php', + 'theseer\\autoload\\collectorresult' => '/phpab/CollectorResult.php', + 'theseer\\autoload\\collectorresultexception' => '/phpab/CollectorResult.php', + 'theseer\\autoload\\composeriterator' => '/phpab/ComposerIterator.php', + 'theseer\\autoload\\composeriteratorexception' => '/phpab/ComposerIterator.php', + 'theseer\\autoload\\config' => '/phpab/Config.php', + 'theseer\\autoload\\factory' => '/phpab/Factory.php', + 'theseer\\autoload\\logger' => '/phpab/Logger.php', + 'theseer\\autoload\\parser' => '/phpab/Parser.php', + 'theseer\\autoload\\parseresult' => '/phpab/ParseResult.php', + 'theseer\\autoload\\parserexception' => '/phpab/Parser.php', + 'theseer\\autoload\\parserinterface' => '/phpab/ParserInterface.php', + 'theseer\\autoload\\pathcomparator' => '/phpab/PathComparator.php', + 'theseer\\autoload\\pharbuilder' => '/phpab/PharBuilder.php', + 'theseer\\autoload\\sourcefile' => '/phpab/SourceFile.php', + 'theseer\\autoload\\staticlistrenderer' => '/phpab/StaticListRenderer.php', + 'theseer\\autoload\\staticrenderer' => '/phpab/StaticRenderer.php', + 'theseer\\autoload\\staticrequirelistrenderer' => '/phpab/StaticRequireListRenderer.php', + 'theseer\\autoload\\version' => '/phpab/Version.php', + 'theseer\\directoryscanner\\directoryscanner' => '/vendor/theseer/directoryscanner/src/directoryscanner.php', + 'theseer\\directoryscanner\\exception' => '/vendor/theseer/directoryscanner/src/directoryscanner.php', + 'theseer\\directoryscanner\\filesonlyfilteriterator' => '/vendor/theseer/directoryscanner/src/filesonlyfilter.php', + 'theseer\\directoryscanner\\includeexcludefilteriterator' => '/vendor/theseer/directoryscanner/src/includeexcludefilter.php', + 'theseer\\directoryscanner\\phpfilteriterator' => '/vendor/theseer/directoryscanner/src/phpfilter.php' + ); + } + + $class = strtolower($class); + + if (isset($classes[$class])) { + require 'phar://phpab.phar' . $classes[$class]; + } + } +); + +Phar::mapPhar('phpab.phar'); +define('PHPAB_VERSION', '1.29.4'); +$factory = new \TheSeer\Autoload\Factory(); +$factory->getCLI()->run($_SERVER); +exit(0); + +__HALT_COMPILER(); ?> +�*� +phpab.phar8vendor/theseer/directoryscanner/src/directoryscanner.php�";A5iG �P��7vendor/theseer/directoryscanner/src/filesonlyfilter.php� +;A5i���;l�<vendor/theseer/directoryscanner/src/includeexcludefilter.php�;A5i~���Ť1vendor/theseer/directoryscanner/src/phpfilter.php +;A5i�\�n;�'vendor/zetacomponents/base/src/base.php�Y;A5i�����0vendor/zetacomponents/base/src/base_autoload.phpL;A5i=I� �Lvendor/zetacomponents/base/src/exceptions/double_class_repository_prefix.phpT;A5i1�MԤ7vendor/zetacomponents/base/src/exceptions/exception.php�;A5i +�F̖�Avendor/zetacomponents/base/src/exceptions/extension_not_found.php4;A5i�߃���<vendor/zetacomponents/base/src/exceptions/file_exception.php+;A5i�i��>�5vendor/zetacomponents/base/src/exceptions/file_io.php�;A5i��k��<vendor/zetacomponents/base/src/exceptions/file_not_found.phpH;A5i(���k�=vendor/zetacomponents/base/src/exceptions/file_permission.php� ;A5i� ���Ivendor/zetacomponents/base/src/exceptions/functionality_not_supported.php<;A5i����[�Fvendor/zetacomponents/base/src/exceptions/init_callback_configured.php�;A5i�̉��Dvendor/zetacomponents/base/src/exceptions/invalid_callback_class.php];A5i�ݛ��Bvendor/zetacomponents/base/src/exceptions/invalid_parent_class.phpC;A5i��3c�@vendor/zetacomponents/base/src/exceptions/property_not_found.php�;A5i���w�Avendor/zetacomponents/base/src/exceptions/property_permission.phpx;A5iWj�&��?vendor/zetacomponents/base/src/exceptions/setting_not_found.phpR;A5i�� :��;vendor/zetacomponents/base/src/exceptions/setting_value.phpY;A5i�A�]c�3vendor/zetacomponents/base/src/exceptions/value.php�;A5i�����6vendor/zetacomponents/base/src/exceptions/whatever.php ;A5i���*��0vendor/zetacomponents/base/src/ezc_bootstrap.php�;A5iNy�֤+vendor/zetacomponents/base/src/features.php�.;A5i� +/��'vendor/zetacomponents/base/src/file.phpHH;A5i�'���'vendor/zetacomponents/base/src/init.phpT;A5ik;�5�Gvendor/zetacomponents/base/src/interfaces/configuration_initializer.php�;A5i*(��8vendor/zetacomponents/base/src/interfaces/exportable.php�;A5i;`mZ�9vendor/zetacomponents/base/src/interfaces/persistable.php�;A5i5��a��+vendor/zetacomponents/base/src/metadata.php�;A5i�v�bM�0vendor/zetacomponents/base/src/metadata/pear.php;A5i�L��[�3vendor/zetacomponents/base/src/metadata/tarball.php;A5i�\�+�*vendor/zetacomponents/base/src/options.php�;A5i���K�)vendor/zetacomponents/base/src/struct.php=;A5i�l �Q�<vendor/zetacomponents/base/src/structs/file_find_context.php� ;A5i�JZ[Ҥ?vendor/zetacomponents/base/src/structs/repository_directory.php ;A5iC� ��<vendor/zetacomponents/console-tools/src/console_autoload.phpr;A5i��i�>vendor/zetacomponents/console-tools/src/dialog/menu_dialog.php�;A5i5lj�Bvendor/zetacomponents/console-tools/src/dialog/question_dialog.php�";A5i� � ���Qvendor/zetacomponents/console-tools/src/dialog/validators/menu_dialog_default.php�;A5i+��Xvendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_collection.php�;A5iwO��N�Uvendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_mapping.php;A5i���F�Svendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_regex.php�;A5i���{�Rvendor/zetacomponents/console-tools/src/dialog/validators/question_dialog_type.phpC;A5i(���9vendor/zetacomponents/console-tools/src/dialog_viewer.php" +;A5i7R28��?vendor/zetacomponents/console-tools/src/exceptions/argument.php�;A5i�X� ΤRvendor/zetacomponents/console-tools/src/exceptions/argument_already_registered.phpE ;A5i�/wm'�Svendor/zetacomponents/console-tools/src/exceptions/argument_mandatory_violation.php�;A5i���Hvendor/zetacomponents/console-tools/src/exceptions/argument_too_many.php�;A5i'Y�ۤNvendor/zetacomponents/console-tools/src/exceptions/argument_type_violation.phps;A5ir[�:M�Cvendor/zetacomponents/console-tools/src/exceptions/dialog_abort.php�;A5i�"��@vendor/zetacomponents/console-tools/src/exceptions/exception.php�;A5iN[� �Jvendor/zetacomponents/console-tools/src/exceptions/invalid_option_name.php;A5i�d��Lvendor/zetacomponents/console-tools/src/exceptions/invalid_output_target.php�;A5i�]vmw�Ivendor/zetacomponents/console-tools/src/exceptions/no_position_stored.php�;A5i��RGy�Mvendor/zetacomponents/console-tools/src/exceptions/no_valid_dialog_result.php�;A5i�X���=vendor/zetacomponents/console-tools/src/exceptions/option.php�;A5i�}��Y�Pvendor/zetacomponents/console-tools/src/exceptions/option_already_registered.php�;A5i�-/ߤQvendor/zetacomponents/console-tools/src/exceptions/option_arguments_violation.php�;A5i ~x��Rvendor/zetacomponents/console-tools/src/exceptions/option_dependency_violation.php;A5in�����Qvendor/zetacomponents/console-tools/src/exceptions/option_exclusion_violation.php;A5ieV��m�Qvendor/zetacomponents/console-tools/src/exceptions/option_mandatory_violation.phph;A5i�YXpA�Kvendor/zetacomponents/console-tools/src/exceptions/option_missing_value.php�;A5iF�^�Fvendor/zetacomponents/console-tools/src/exceptions/option_no_alias.php ;A5i�����Hvendor/zetacomponents/console-tools/src/exceptions/option_not_exists.php$;A5i�6E��Svendor/zetacomponents/console-tools/src/exceptions/option_string_not_wellformed.php ;A5i��0���Mvendor/zetacomponents/console-tools/src/exceptions/option_too_many_values.phpw;A5i ����Lvendor/zetacomponents/console-tools/src/exceptions/option_type_violation.php;A5i��D/�1vendor/zetacomponents/console-tools/src/input.php��;A5i�&ԣr�:vendor/zetacomponents/console-tools/src/input/argument.php�;A5i�h"��;vendor/zetacomponents/console-tools/src/input/arguments.phpt";A5i�ث��Jvendor/zetacomponents/console-tools/src/input/help_generators/standard.php�8;A5i� :SJB�8vendor/zetacomponents/console-tools/src/input/option.phpJO;A5i��N��Evendor/zetacomponents/console-tools/src/input/validators/standard.php�;A5ix��=vendor/zetacomponents/console-tools/src/interfaces/dialog.phpT ;A5i/Z;�Gvendor/zetacomponents/console-tools/src/interfaces/dialog_validator.php�;A5i� ��5�Kvendor/zetacomponents/console-tools/src/interfaces/input_help_generator.php�;A5i^��]�Fvendor/zetacomponents/console-tools/src/interfaces/input_validator.phpy;A5ibutov�Lvendor/zetacomponents/console-tools/src/interfaces/menu_dialog_validator.php�;A5i���T�Pvendor/zetacomponents/console-tools/src/interfaces/question_dialog_validator.php;A5i��&c֤:vendor/zetacomponents/console-tools/src/options/dialog.php2 ;A5i*�Y�?vendor/zetacomponents/console-tools/src/options/menu_dialog.php�;A5iw1v�f�:vendor/zetacomponents/console-tools/src/options/output.php�;A5i�0ِI�?vendor/zetacomponents/console-tools/src/options/progressbar.php�;A5il�e�%�Cvendor/zetacomponents/console-tools/src/options/progressmonitor.phpF ;A5i�� ��Cvendor/zetacomponents/console-tools/src/options/question_dialog.php�;A5iN�ia�=vendor/zetacomponents/console-tools/src/options/statusbar.php� ;A5i�p�~[�9vendor/zetacomponents/console-tools/src/options/table.phpL";A5iieK��2vendor/zetacomponents/console-tools/src/output.phpZM;A5i�ᬲ]�7vendor/zetacomponents/console-tools/src/progressbar.php�:;A5i[m|��;vendor/zetacomponents/console-tools/src/progressmonitor.phpZ;A5i���q�5vendor/zetacomponents/console-tools/src/statusbar.php ;A5i[ ��rM�?vendor/zetacomponents/console-tools/src/structs/option_rule.php�;A5i� ��Avendor/zetacomponents/console-tools/src/structs/output_format.php[;A5iXU0��Bvendor/zetacomponents/console-tools/src/structs/output_formats.php�;A5ib!-�1vendor/zetacomponents/console-tools/src/table.phpBt;A5ir�e�5�6vendor/zetacomponents/console-tools/src/table/cell.php;A5i(Կ�5vendor/zetacomponents/console-tools/src/table/row.php�0;A5i� +/���8vendor/zetacomponents/console-tools/src/tools/string.php�;A5i���F)�phpab/Application.phpJ&;A5i� ��l�phpab/AutoloadRenderer.phpc#;A5i� +��� phpab/CLI.php�_;A5i@�]�phpab/Cache.php@;A5i� "9��phpab/CacheEntry.php�;A5i���Ф"phpab/CacheWarmingListRenderer.php�;A5iry?���phpab/CachingParser.php�;A5iOI!��phpab/Collector.php� ;A5i7��6�phpab/CollectorResult.phpT ;A5i~�-���phpab/ComposerIterator.php{;A5i�㻂�phpab/Config.php14;A5i ��Bפphpab/DependencySorter.phpm;A5i{ɢ�p�phpab/Factory.php� ;A5i��#�T�phpab/Logger.php�;A5i,�I9~�phpab/ParseResult.phpg;A5iX�ߪ�phpab/Parser.phpnT;A5i�����phpab/ParserInterface.php;A5i���phpab/PathComparator.phpw;A5i�`=Τphpab/PharBuilder.phpg;A5iN61_�phpab/SourceFile.php�;A5i��%��phpab/StaticListRenderer.php�;A5iy���phpab/StaticRenderer.php�;A5i��f�#phpab/StaticRequireListRenderer.php;A5iL�;���phpab/Version.php� +;A5i���j�"phpab/templates/ci/default.php.tpl;A5i /]i�phpab/templates/ci/phar.php.tpl�;A5i�~���� phpab/templates/ci/php52.php.tpl�;A5i^@�N�"phpab/templates/cs/default.php.tpl�;A5i�Bw#��phpab/templates/cs/phar.php.tpl�;A5i��2q$� phpab/templates/cs/php52.php.tpl�;A5i&�Nˤphpab/templates/static.php.tpl�;A5in휺��"phpab/templates/staticphar.php.tplW;A5iY�.�֤�Yms�8��_ї���f���%��q@Հ��&���Uʱ��H�$�R{s��J� �@����U_�����ӭ����������_��t:SЈ���ݻ�����OG0��,b(���#���}q��/Z��20�J����Q�c�J%���J9��%��)ɗ"F��>e�x� sق�T̀ �ϗ +���h@In�wܐ���� �]�^��r6�tHC҅�k妑���`H�N�qC�hxkf����3�<9~H;��kM��?�b���C��{ +��rM���3�D �_��^P�r@���[�R�tB�l}ա]�Π��t�� ��p4p�[���5��ۘ�!u�u�� �Q!�ŽvRg쓡6��iU��2i8 \y^�0��vHp/0č҂�:-�~�{=���rP͟�Eݐ��xR�mB߻!�ć�3H�p��s�'���j2�+Zp�'a��@]��5q��#}� �#=B�K`�%WzE��o=���iB˧�C��o�[���q�8 �e)�[Ƶ@{�t��6>lB� j���A0��-�������h�zYuS����%�#�P���R͸0ˮ^e���n5$Z�*|���4�]]��{��7Sjq�nOS5[ޟ�|�V3����N���d�E#�3 ���8���Hk6ul���B��Ҏ�p�4� ��4}D�߾H�sXDj�έ�}���E�I�)mI�V�\fJ�}��"g��8[&y����z)��I+T��+�]�cu=��IV���a$� ~�����?�")�� z��\�����/�v���a�UX)1S� p��^JO۫�� +c݊�j/ ����C�*����*��0��ES�Ck�)�L_��u�8U("�;�˳Tb�}�~KS��f��L~����$ D��`G�W�*�+�lر�D4ݚ�����Z�$�''P-�G�&�1,�4�ɒ�y��$4���gi��k18�mȏ�X����0Ɯ�}ً_�ڀ[�P� �u~�'[jrj�Fܡ�V-D����z�`�����u?ߺ�{7*v��2..@�%��嵈�:x*n�Պ���u8�~�6k��*�#��� +�=�X����o�%�ܒʊW��F%nk����3�;{�yѰP���,���s|�W̭�y1�烊y�7?��kԫb^U�����aU���_+���.-;�����^T��׋�5�6�F!�^3��o�Ϥ�YT��3{�y��c5ò�>���Xpbt��H_)O\<�F��U��js��UP�f/�t�qU��d�&,��0�a�o� �])N��֦�n�F��t�q� k[}" 'Ȕx�Y�J������I6e�`F�4��=�}��j�ͩ�>&�9}(k��e��w]R[�ZP���3�FJ��q��P�ߴ3��D,����M��������G��]�q���\��OG���O�����e��DV�E9?|[R�^¯��4�r�]��^u��̓���S�lV��k0L�1Bo ᨿO�b�Ju��wp���%K^�8���qv��pa,��:{)��ؒԿM����BfZ�g�#�9�����0��u`۶�y�O�Ge� +��Żg^�����x,{����4��[�f�Q��@̗L56��M��zVqf Л�o���]u�-EE��;���ÃթY����w����妚A-k���v6����7�s����]gHZK��P��.�A�@���%wC'�XS�#���Y)���ʖ逹E咛��n��#��)|����ֵn��O��`c|s�@~��.�u��J����W ���(�X��� +Y"�����/D.�n.b�4��V���7�}E���w�P���������-���3I��L�?�ۃ������f�����7����E�|9�7�VQo�6~��8t+fn�{YSt�%:& �I% �a`�sLT& �N��i���t��/"y���x���/�Ūwrtԃ#�����E�~3�W/_��������Q��t��� �]���-���Y�A���У���� �c�}p�z�5�L k�� x�v ��km����uK?�;`]��u��m�\7* #�r+tK��r�V��BX�a�0�]gﴹ�ƚVG?���^oy�g�<���Tc[���p�6 V]��h�)el� 7ha�=tڇ��ش�Z�N�%��`�;.;6+g�u��!����f�D��;@e����:X��N��?@:�佗�~������H�Œ}4�-� �u~Gd���c!�,�i��kf�����L�C�N�b sg�E���;�p�+3��&������by�M�y����P���e� P3�.hA +]������� + �dU9�$��Z2.�Y&��g��Td��w3N�ƁNg%%\f�g��D �VyY�:¨�IM&��S*I� 7�����0%<�d��F���*ESYňc�!�Y�%��2�iV�b�y��))��VP1 �� &YY>�10��n(i6*�&\u�$�1��QN Rɬ�����yG��2�W)Cƣ���Z�JҬ�"�f�D@�@�u�!�5'�H��#��GBRYK�IyA�͉8���$\-��Lf�h�q6�R���4��h% ��LRV `�.��g� EҚU)g9!�_E�(F:�!\N���JOq.�r�i.�w2�q��,T伤��I��tI���T�=t�2�V��ӡՂl�{��z�5�.�a팼_��|�� �n̩�Bz�ƺ �h@�B|�,���Uk`�;��IA� z�y �C���m���X���g;T_���������m:�}L=3��� +�g@�zx��U�o>)��¦7��F�w Lź���A��[���I�vM�"/A�`�j�{;���\:g���Ce�L'�����T1��ɾZ_w����4�?�����N�f��>��o�L��oo0D����#I�<���~x��9��)����6<|�������#�;T�J�/p����w�? �%~�s���Wb�U翚���aS[��C�/�VQo�6~��8t-�n�{Y�t�%:&�HI' �=0�9&*�E' �����ԸN�6C�Q"��>����zY�ww� ��o��\:;��ի?_�~��Y�0�����5�VZ�G��^��uTU��ؠ��ro�a�g���)�A�� ��И�-0��PZ�X�jFp��� o�v�2�Z�Bz��ǔ�F�R�a �5W���R:pK���*s��%F���5�h��M� �qk�,zR�)V�ƁE'����\��^)m�*pԢ��j�R��8��u�ŪTMQI�B�� 6Jo�ҳ��)��*B��Z�b�B��=��徱`�-��C�d��m@ظ`��f��`��h�BOl+ô��n:�-��MOd%o�}"�� �.�m��Lm��8�V&�@�V]a kV�"�Y�ki��Ӭ���y�U>��O/�&Z�lD"���'�,b(��OiB������9��S������!g��z�1��F㔴�sH(#��ݍb��LD������{r2K#v"̙����$4J!�N�c�a�%Ж:~��9#'�x>�P|>悊� p��IP�vJc� �yn���HD#??c�� +~���9�^?�E3A��ͳ��g�0��9'I�:�B�bJrv�q�a+Fp6%bJ�,�b/\�����Xl������`!#�)=&YL�l��(';!��~ m��E��}�a�朴Ít��:�(9��|�8�D�9��'����N��dղ�(/��DY,��7��Z� �r�Ɔc�c7��]u���c7U�@�fc�@�~`w0����X"G������������[[-nj��T�m���+�����yӞ)m�*qء��j�V��8���IT�j˺P�'��҇��i���%�_�.�ʔ� jH��:5�[��M�Ъ�n  +�9L1C|�]l��Da�<��]����>�M�K�B��@]ۢ�Lc��8��&�B�V�a+k6#�Y����l/����� �������ֶ��  �X�#N� +�qvC��hrB f��� �&� ��b�ING�d\��H/�������3N�ƁNg)% �#ΣLR"�@�8��]a���&���)�$Ɇ]h�g`c�O�LF#�R�������c�!�Y�%��4�i��|� q�)IN�f�1 7$� &Q�>�10~��Hi4JIw]���rK���*� �d�A�HL���'�Y�EȐqO� ��$�4J!���5�B�v|�✓���=��GBR�K׌%�yA� ��8���@\.��HFCo�q6�R���(���h& ��LR� `���p��\�$pͲ����דJ1���� �@�Њ=q��CHNcyx�q��˃d!#�)�&YL��y�9d�ũ�ghw�l "�';��/�)ʏ�-�gm��MQ��b��Ɔ��}�걫}����&\ժD݆�F"������i�zLS�r��~H���� �Bk����~dqt[��C�sU��зxޙ����ƪvh�C[8�� e����h��~ĬT�-, �Ìm������-q;�����Z������«��ݩ��[�E��l2{�~r��><��q� �ϒ8E�6��WX� +�~�a��g�7(]�� +A�)�֢v�n@ig®��'��l�2,�����ӯ�~{N +��7�e�JXmu��� ���#�\)�2p��C��iJh6fL� ο9���u�1m��>��2����r�mp|y�nV��Wx0�k�����fݼ����=�� +��������B"�/�CO-���}���g/�r������sBW +X _�2F�D϶��5,>E)Ѥ��À(+(��R���p�^��w��|�(���.nF�/��)��J ��w�Ma��Ze,!ӌBF�(?-&-~��Z0��ygK���J�9�����P���7��������o�|w ��^_�^܎G7py g������� \��Ӌ8�o��>P�T��H���4 ��်b�$W4a3�@F�yA���� +� VT,�D�J y +[2�UJ��mn���"��������1�B�9�����S�ݥ�M�������r�jV����]R�੄�����(%���C��}�%�, ������$��x�����CK��H��)͓ $ �ܡR!^����p���ϊ�������K磫��/W��ގ.nƗp ?����W/o�޶��ѵ[ڎnX���\Q#���i�h���)m���|4���<wvk@�dJ�i�W(�0�G�Go.�ގ.n�~��)4Q����*��C���T�AM�8I%��� �:F9x?����y��J�{�pQ,���M��<��HMOό�2�$�H0zܽs.6}X/X�@�S��� ���o�D�1 �*�}')���Η�`��ՠscȋ,��.hVd��u���%5���M��:��.>g��Pñ�9`�����<H���;pS��,|S�ܭ�H��/D�)˘ڀ�D�\��R�UI���QUy�ܠ�IW��_i�������dQ���As�L�Pd)Lщy:�A�Rt�T� �⒡�Ι��q~'!cw^وd��1�:g�S"�d�Z�0��d��t�>Ôf<����F�"�t2�l�����P�Y�?!Y� iz�0����~_��\#��Dh�,Wt����5�.����F���'���#�Y�۱��ߴM��{"�J��3�2㾜�� ��7�(�+2�8h9]�:���/4��|&�f���� |�4w�����Z���V�g�!<�� ڙ3�b�� r؞�ʨ˕��\�W;��Ѳ#����3L{܌��z*%OQژ�|�����b�5��"�,2�\G�[��b��fEn� I���{ ��M�Ԇ�?>H��u�D�A�{�A���=���,������So֐K&LAU!�ɋ��K�3�� ��&�L0J6��4T�:�G9YR =�T�ԝw96�w�f�eF����9텽�"m�qw63kj�,�\��j@ �0�<�7������cv/D�*K+��#IՕ��т™�u� ��QoM��LP�n@{j��Bd��A�����L�g&� q�HUL߾E?&��8�� +:gRQ<� �"��h��� ��u>��|��c�L�����c�����>D������G(�`9T�r��o,���f��e�m6�����_�Ȯ_��x}��/���4F*v�>��� ���(ogLH��_c�I�m�I���]s�vKx^�J�{ \h���HL+A�%.ۃ��z��������������>��_�~v����--���A��8��hϓ��U��4����S��O�}rOX� +8���5�=��w�g���4,�h�ߎj�[������f�H`ҶiF�H�~_Sу���/>=L�o?~z� w`�e3t/ޏ�0k��L�S4�"��,׏?|�q����Ӹi��C����;}���й�|>x�,�w�ܷ���K��$�bI=YN�pF�_PZU�X��o�f�Ӄ„#�߃Si�Y��F�(P5DF�����U�y��N�p�l٠�0����$�2��Oѳ�Bw�e >�nw[tFr}Q��Ӈ��O���aǂ�V4�� �GN� +���L�\goDZ�T�$\�o�O%�|Nń +����%�*���t�ݹ�r���9ˌ/��[���Lv���l��Xf�����ܖ6��c[��V:\2?W�>�V�#V��q�4���]��P��J j �Z�=k �:>���Y�_��R0�WoG&��Z{�?���>��ʼ�B��V%��`���Z�,g�`���)���qA�B0�:С�'CO�gQ<��W�h�g��ߓ.41ܐ}��d���B���r�(19�W��>�=��G>���4�FAOq��X}���6����q�iK!��dIż=�Z�]�u-����q�JPmu����ɮ�Ї�{�n?J�7�֚Oj�D;E�6���˝y`�'fs>�h�1���$���ƺT�hxߥ��H<��I�N���*Fj�*��mg<1�-��-�������_h&�Z����њW(��q�X�s��-��ᾷ�6FIleL��UyX�G�rp�}J�*E��ʟ��i>�Wς�����Ϝ*�Y�^�}c�M��7S} �؇�K�gY^gk�șxB>v��I��'�� �������~l���ꕞ���zro8��,���U7 ���Ȕ� f�X��ZYLT�uq�'�z�>�����nʋ�J��4��['�|-�]"� +��vLɝ� �o� \I,�6���Kc���2�`-��x�Bv���+4��f�� �v:�q�Q������4���7��l��5a������X�67Ept�+��K� ֙��1���&z/��dMue�kŌ�J�3�"v���\R��&�"�-��)�^���Z��ة�t�aT$�&K�%i��I��R�a�^����*�)���k3�}xѤ?��c O~���5��\Ϸ@5��#�)[d�*��Kp�1��������w9S�T���V�[���"�� ��>�[�qg�;���k�BO���DZCHp)�hu��VD�r��q{�a��8%l-�k�dkm��}~5�U�~��ϝ=�� +�{�� +~G��.��4�\閳���A �_�ZL) ��b������U�n��e4� vե/S�]e��xt����v0���AG���Y��p�R�Ûv7�ƞWM�*��c�����C&4�q&_�\]�6�� +s_�wO��$/��)��P&�a�����x���l.�륤�t�����*&���d�ijQ����zQs��#� V��Z{ cص5p1�5�N��y6)<���z���n�ꫮ�����dKQ���h��_��4,R�)޿�y�<��r�i�t�~:��aX�� ��Ak���7�=��Ƣ�}ru���+��x �������}>�{�Bp:ׇ��q�_Z�y��=���.��0��JV>t���1����1"�ô��0.�6�Wo�ʚ�Ȭ��CQ/k�Z�e�kl����ԕG �*r�L��i�5�@{1gN��hG�[�������8q��^��.�v����f;�^mS���QcQo{[�eX�k�؀#��V E�0`���n�L�G}ۆ� 4i�ho˳���W����vt}q��_���]K��ێ�i�K��Dii[T��5cHe��ҍ���ԾE(E9��m�� �������B���V�AkK2���n� +���� �8�E+㙩r�,mh�G�5�a�-��A�?ɍTt���䷸"wh=����!��x�l��(-���� ���g����ܫH��W!��I��Є�uv[:�Zm�5A��Ꞃ�Ι4Li܉t�t"zGzi� [0�AK:}Ͳ ݴ�\B[��Pb_)b�L�K\��q�9�z��AT��qmh� Ή��"��諳��TW,�T�%\���V��r�����-��ַe_�-I��~*��w�N�Zߺ +�ԗB� �zT�a�"hU0��7�o@��7� @ �8�H�V��:oiG�~�/a�!e��חݡ��F�� ��� .��^� +L�S���ml)Ձ9���ğ�}�K"(��V�E���7�zWE��. +#)�M�r +u1�\"�u��}Iz�M��4=��? �'}L뫻���/�W���8�dfTa��ܱV����{l:���v*���7����� @��|]v�-.7��t�@�m�������C��@�!��� /ğB^�����b[i,�a�Wz��D��Bв����^���0����eS3V�� /���(C��M���:"���<^��*�����K�,H��R[�1�ؾB��2o7p�]��� .���n��Y�����r������]�~�IK�5c���Z0�E���yֶ��j\Ry\��2�س]�~M|�8����b���3*/O���͂��$�� ��y��$e"XuK�y��qI�>p���ҩ��,)2�q^�5�l��1DWl�L��A�άm�5����y�=�b��6�<����ۙ����-j'��45/����|��nmK��Ay���@1�'L��Ƣ�����0M��ud4���n���'^������3�Wo��~΋iF+&”��j���f:*��zc��5u6��tV%�)v~���������ӷT�X�m����{�����~��(!L�F�����eQ��$)��E[+B�;�ZS��cdI-�h{�/ q �e�Ȧ���j?�,�R �rه�����ף�����������-6"����qR�Vu ���Z���W{�Uv��Y��{;}/g_|��$U�ft�|aZ���s��:;��6��3�w�+O�7�?ŷ��k���t-X��鶡��u�is=V�ʗȹ?���Uw+Reۮa����,��VUFn�EX?�*v �.�����}������(c�S��va}C�e��+.%�נY���yW�kT�CW����m]�X�X���e�y��4BC��=x�,$���z��W�ѷ��G��9v><{u����Ms�H����._�Q^��q�MB0Ԫ6 .�ĕ�H-i�bfv�eL~�� `{$NP���O� ?�R���\��fU)��@F������+\|EK���V�$�5�DJ�R���HcZ$*� ���e�t1J��PK�W��ZX+㰒�Xլ T;"`a��$�"����x���>v�� 6�K�RX�(����,�9`B�ʬ} Nh�@� Y@��ֈ�dPIƖB.�d�cw��-+ت�I�(�����u)��� .��yzv���׸�jK:�SJ�AH_�J�L���n�c𳁨���>P�� 7�(���Q��l���*SDm�ѷx<�%�?��5��"k���0��j �u%R\Un\�|�|����,dq�Զ��&J�(�3%}��F ��|%qr ������܏��F�EjM��E +ʢƂ�P�d�Mf-�k��Tb-؏�u�W���ȗv��ށ������waͪ �XD���Ȫ����������\E��!��4��s����?}B�s���� ΝuD��=|�R�_?�NE�r��RY��ەՏ��Q�7�^U4���;�� +Vf{k(OG~B��+���.�^��^p5yb���3�~U �Q.��e���թ�w�^�fo���S���߲.x'����صLw����LqRk� ����c��߶ڀ�X +cU�0}+���6��P!?��]��t��Nb��������=wv�UG~�.��ޢ!�x_;�K;����^��Rȁn��������;O �;�N� !��){�o�?��{vg��I��r�D�G2���7�2��Lz�#�ڙ�*ɦN����<�9Ex�Y� ժ=���{�V�i��q{A`%~��C!�L�)�(=V.�A<���s��:���^Zʄ\:��=6o�;���-:�D8Q�T�l�$�S�Լ���Ʌ���vŽ���v(�� 2��`kb̐��tKh���� 1_�"M��@�ª� ����>���מ�����2�=��n���} �_���:����~�a�����T�n�8|�W �N �T�1=�ug\a�ۢO�JZKDe�GRQ���~ %9n�.z1���rfg��[]�(�L"L�5#Wґ�B�p�����j���5Y{�ZY�9|4�����J"�����YZ.�T��i�+F�v�%�X�F`W�ty�Fl�${�2�+�]ƈ�qʠ�A�a޳t6R�@��lW�v��B��Z�*�JX��|�NPQߚj�Sf.⁆K2��+}0��T+��J��z)�r��툇�N᠚^ʙ�ތ)>��^��%�\@��:�~�{:@*���;8� !�����<�{u�1�'Q�$(H�ڝ�~P@圾I��mc +���)�Aa�a5_�����=䓬�Z��� d�ֵ�)�5�~~aLa�B�5� YN=�8ғe���递�0��,�*��,]�S|Ym��|�����n�ޮ)6w�oַ��j�N�Yb����ַS�p��6^�2�O.��4��g���՜���Q�,*��g�D�� �kA�@-�…H�m���>�Ӕ�T~���}>���J�I����G�_ы0I���~ w�Z��b��lB`�9��~{�ul|�<̉� *AN��*���0d���%�(�2��)�������eqœ +�c�%�M0W�:��΂ �}V�S�:��6h%��~S^dd�#��w�q�VT��sO{��[a���/ �w� ���G�C�����)�ҩ?���]#� �۷|p�jh7}��^��:t&�O�a�nn~b���"IBb�x�>�qu�?�K���9��f�E ���Y�*� +��x6�[�C~Ǐ���8��u�q����7ѿ�T�n�8|�W �u��*��4m���׳��mѧ���Ң�#�*�C��@Zr�w����3����7�lm�|<�0ƜAk�BM����i� �6R �'�KҞJ���VȚP�m�#�M�K�p�i1�@�Kr0�"�84��S:޴�8�=#D���O��(�/W��� [V _���DǡF�٣3�;��A�%��B��ָ&��*��(Q�s\����|�v���b>���C�`�3m/�HuߌK|!��דW�:����g� ݈� h=�d�6�5�i�b�eB��9&����l�]I +��8 "�Fu�*ϻ���T�ĸ*���e1{�z�|֊���?[vTb���V�EP���%�����9��ˈ�����eC�� �:�Xg�0-�%�.ֿ�>��uzw7]���;ܮ���jY`5�t�-"_,?^�8��@�EƁc?�<����8+�Kޒ�-K(��VT��� ����k�Gc=�.���F�G艶aG�[!�G��G��G?y.�`*�y�����V���e��f�l1�41i��a�L��fYC(�7����ܾCq.��{ �'�%yI:���<��a���I�t�q���� ��g����7佨���7���u���׶��G��]g�io����2�6i�NkKy�g�a��N4�c���AO*ٶZ&��{9��H�{��Ǘ���g������[�`k{��{-]��/��=�S�T�p���տ�s}~<�#��W��Ш�gB�Z8���1{�޽���T�n�0}�WUH몒L�я/�Dv?���<�}���iV��P�x!YE� ��J= �7������gB+2��n��,ml�o�H��r{�{��]��}�7�MY��)w8�9v�sKd��< +{�V�4I{z���`uH G�����j��[dM�Kp�w����!��aG�����ʞ��}O�_�����m��T�n�@|�W���F!n+��7u��$R����bo�U�;sw�[���⤩���U�n�8��+F�؁�*zt6۪�����Ӵ����%"�%�*i�_��b�u��b[� ߼�G��Z�*����W�L +˸ࢀ- �-{� ��D�w)˥@V1cx���0��J��JB*w�e�p%�3G����IC +rh�QKݝ����R��� +MT��f�D�~��$�;^y|�M��-�%l� Z�o��,Ϲ;�U�b'u� q@MӹәIu�yQZ�V�6%W3`㤤WC1�#�������1�G��I~5{��-=hԯ�&]�{i�ڳ�|��2Y��3�yt����'�[����;�f{���Z5ömg��;����d/���W��=�ZTd 4��pM9��`JU�v�N6��4�iD�)^\obH���}��3��(~�VM�8�፿���jvx����ys�|��]�]?�{�K���0��.�1-�Y�q�����~�{2f� e�����N�[�'v�Q$@ZK�͈��)�����w_�����'��&v{�%yS�oM����=�_���ʹ�%������w���f�@0�xx3�$j�'�@�����aP@圾MӮ��M�)�Qa�!�[����/�䣬�Z��� +�`Zׂ�]M�Y����/$:#���ܣ�h��!]Z6(� J�� ŋY��"��9>e��6�����_���2��w���l�m�96+,֟=��l�~�":h�E(��Iŕ���W�)YM\�G�dٲ�P�od�bh2��~�L�E#\��߆kK�>�Ռ�T~�B����4e�S%�4 ���?>��a��K��B �o�:��"�`EePC�)sD�,�aҞoGP�$s�Z�B��t��_�i^��k��#Y<�t>�"R�7Ý�֙�; Iݳ�ɀ�o53��7�,�f� +�d ���;�<pGM���!k}�c$l;�a��O�ユ����·^C�u=�$����i� ��`��5nn^��b��@5=/�B��j|!8E�C O�k|2�c��12�����Qb?��sէ����ж� �j���;�,��H��Ƙ��N�)z�k�7�U�r�8}�+�0� dX��#�lK��e�  ���#䋭�-y%9�m��;�m )M�I�t���\��wy�����Np!RW�2!��a��?0Cn�t&�J�kN�J��̘<���$ E��C�9� a�V�d�p� +1� �]2" %ɡ�F�tu���*��b�5QFҚ>0'����b< +���G�T8�P +��& T�+���H��Y +!WJg>�39�\�-��B���ID�N��� �T�ͱVa��Zʞ�:=|&�R���7��ă��j�{���@*��Ў� !�U���I�ѵ��}�KM���v`^ +�j�� $�� (˲�|�}��Q|���<��m�M ��)M�BS��,�S��2%��t��e���Vȸ�Ц��~�v)k��%�|���9��6> ��y���������l8Y��9�3�����b<��1��p��!�O�{ aҠu���!\>)�sS��J]%�+��2,&�ꖴo�|� LFHE&�������<���qT����m� `�U1� ����^�Ǭ��Iд�/ZZ8�kUJ� I�% ���V˔2oCGǼ[{��&n�޸��eP�ZS�\�A�_,� +�֖dto�v���^�')i�.�5`�T:إV9i�9�^[� �{p$Y�*����9�,s��/�rfe��M������Q�"��Q�GڄYW������?:���p��p�z6^���t��?��Ꙙ�����J?4 ��~���$8#c���͌�im5ۿ�x�W�侦_�����X����d���zd�"7L),OЩK��.춸����*��m�p����3��]p�͇ww Τ�����;Ss�V��¥&vs�Ԡ�^-���qT��^�������T>~J0������x�d� +aU��i����b�<�n|�����}m����ɦ�km?�n�d�� �ǻ]b囼� ~����43���s�I���������3�ѭH�Zw�w���T�N�0}�WU{�U� �4(��P��2�r���"�=�!t��>�M +h�yI��sϹ�v� +D�A�f�$�RX�9lA���34�Ej���v;�6����R6}NI��%3& ੮yJ�P+=�X�� $rc� 3Y��y��8��Q��4� �����Z4_�Vj�{F�\U$� ������x2ņ��q��Q������ԏ�H �e|/\l��|!�)g:s�S���煅liSp+'%�uŘ=qw���ʺ��Fuی!~�6N�Ix�#[xP�]��O=�b[iQze�6� ��R%g"��V���oI����@n�n��Q@a�EQ�4!���R�Q�0��'�y2�z��[Q�1����2��`J�th�E�I�-� +���)��C�q�8��b���w��jq���x��W�4�b��b~���<�b����!���!�ۂ4�Yi'Bjp�O�ޤ���e�u�(J���(��k�r�Dڏ�"]q�5`"C�+n}��������s��GG���xj�E��2'E����[���DA7�O�8w�ײh +r�r! c)s\7W7ش$h��9޸I���(��'*�gK";  �K^�{�Ha��Sk� ���!aK�1�+�Y�R��KE�8m��ݷ���l��Č�~��k�_K����i'��p��@�����ݣ�&aG�w��K�9c�Y��b�Fxi9wa�Sϸ v�����T�n�F|�W ��� ��MEB�`* ����0y��C�����)�(�|!@������oo۪���<���V�D�*�*���'˩���>P~���(eg�X?��:� +yM�F4%ge��Ӂb�R^12}t=�Fw���^f�t�`�أ�A��y#��i���* s���Ș�v�OWk��B��zq\%�6�8j* +񭩆��6M� �d +�;���HY9�^����1��R��8�=�m��Iw����a ���zɯ�W�vU͆���7�� J;t����a��\7m-���]z����D��� �8-��(�r��M���c +��ڔɨ0�����l�������j�����p�� Զ��t�5�޿`S�_z#NT��h;F`j�����>+� +�-3�� �Y�-�9����������r�O�vwX���}��f�m��~��?��X\���/B��'�4�3�� .ٖs9J��T�Q�(�76ሴl��X RjiąH���_m��w-�������ې�$���U���c�_n�Ϣa�����G[|ҍ���Uȩ3'�.Y+�y�|`7���C������}���=Sm���O��_�;���[L�@�R���X��ˏ�{a}��c��u�˝Aq���i޵d����*�˓�h#�(�/-��-5<�'�}�T�|���s^O�?a�M�8+�OK����}F6���� ����ډ��zn�G�p�ǫx��7��c���=��T�n�8|�W ��>��cz��u�p� D�}*��JڋL�H*�[�� Ғ��CN/�I�pgg���m�6I��S�H�PF{-����M�'Ǚ��{j�XR��H�-rn����b4T�� }��qo"ɢ%U3rS��,��t���\�7W�t�Fs@����J��:o,�##���{��́�9ү7�l�B)M��8.Ћ��kq荽Ci,�($\M D���c!h�"[�ʴ+U�az����΁m��ߌŸ#�x�78�n�r�zh� �uA���+\�:�&����MD��m<:�O���e��2���*�u�;�����삋�(���E��3|ζl>m�yq{�Xo�U��-����l�m�967X������ ,�f ~hma,$����ik�2��ZVR�BC��bT�m I�v/.�@�@#{�q�B��m>��]K�.P�xŅ�a>Ҕ:o*�i����U�5z �i2&�)��&��kkz )ArL�1�a�%bMjx����=n� ���ʇ�Ru6��� +O�#��_ ~�഑|O J�K���������������@<�k��a�u����˾��F�a-��e�U���W5�y� ��ѣ��dY���g��������� �]|g�A��� ��B"��^ �Y�[�$��7��ٖ�x>�՛X�c��=��T�n�8|�W �I �U�1=\�6N��>Dn�> ���HIEN������8h{��E�3�����oLm�t>O0ǖ��� V�*��@��;�(S7���oaI�u#��%�ZA����KR� +x�+#dM�u�{a [ݩBD��*�^�SYhE�-Zm�,_w^[4#De�ZR�-��(����l�A�M������5;��~C�-DQp�Z4`Uj��D�R%l4Kmn-W���YW�Y� %�Nɸ�x��k��n�r�z,��Ⱥ ���%�}A��tv�:�[q �=:G��Xe��ԭiX(ѣ��;����D_� ���4 F���2M��_���R�*����f�o~{�|9B>�����:�T��˜���n��Ѧh?+��=�j�nj�S�K6%��I�Vѡ�*G���n�g���ß��|^]]�v�l�c��~�>;d�]���ݗ��+۽_���dAGc�m���T�tӔC��%gHr��PU'*B�o���0d[v�X� +4ܲ�-��Gm˱�o���U��q3�G����T������o��^�y:�����Z�Pu_[�+p ��ø�N�pa������p���@��G���T��p��%e�5�Z+�m'}p�9���Sx1���w,�N�o���EhHU� IO������2�߲S2f����?�)�� ."|P�����OxfC���)�� �&_:����[�j��QZ��v=��Y:�g��3\��Y�'�ɛ?��T�n�8|�W ���T�1)���� +W�E�6�SASk����T�ȿ��Խ.wz�D������յiL��� �X�� 5{�Xq ��|+}�ڐ��B���Z�K2^i�l�s "�%�U�:�FȆP��%D����E�>G�Yh������ +���^[�GF��u�ޥ@I��6_��Wm�W�qTaP��o�à�7쵅�*R����v���T [�R��Uu�&�eR`���w$��z���G)'��f\�3Y$�L_��74��ί"�����b�.C1��L�ˈ�=�H�/#��� ���i����e� Ð�Xo�m�M +��rU���/�#���,��+KvcZ%Ů%�b�E����1X����85�W˦��-@3Dth�(��3�]�yy��|�~�i����͢���,7Ż|�o��5ŗ��3/�]��oȂ� "�� +���d��¬�.9CR�D+��EM��ٸ�l�\0�Ap�Vu�Ǒ +��Om���7F�o�*�U<��#�D�uM�e�|���nտ�^�y6-��K�Œ[=0�����B�5����f�:� �$6_q�ԝ����Ya�W��?�ӵҽ'�?$?���5�R���54<�=�‰�#�,��h|��aE�0�\C�#>���7�,��=˘��W9�x6�Lj��pa����o��B���y�?�|�#r<^ՌwT��I����c�X���c�}���[�_�`��~p�}�ԟR��Z�)ת�h ��@ �X�N�r���:6�Eg��� &sʦ�� �'���2�9�^��;r!��ۧ8�/�k4ѣ%�B��|sܚ���wj�؂����/W�X�����g<6�w���d���~��v��րAR{�N�N~?���o$�hH:�^�L� +�ʼ �������� i��7��:�߼��:�,UKF��o�Ҙͼ���N�ɽ�o���yԕ6퓍}`�[5�$�lv�8�nNKz�ӳ=�uu������0T��j/�Y1C�- 1~ ;W�����>O���_�T�n�8|�W ����*��ں�� +W�@�^ѧb#�%��#�(�"�~�JJh��"�ܙ�����lm�t�H��F5���@J+]!� ���@�sA�jk��t�\�l�2EC�/�gU��\"�,5#7�Гc�w��7st�d�9��Ck�P�S7]0���s�:�%�3 �v�Ϯ�8�F���K�*�������q��T155P�`\+�D��\�����kv�Vv 죔|3��)m08�n�r�zl��b����W8��f��l�F�-�M@���,m��(LkE����!��6����H��N�@a4 +�C��i�����ޥqU:)L?gW�m�~�z�j�|� {�w�q��#��Ft�0�b�د4z���\D��F�ԤǖM*�$�h�84[���>��,���l�i�e������v��s�q��~���n�c��j�-"�̶/�*���w�E�A�~ry2MS qVF���BT��t�QŨ�-;YˮU>�A�D�Zd�|���mڑ����*��܎��S�NS9�f��[���K�H�En�Uqgz��fͷ�'�4� K>.:�XK.���5B�A��1N������"�1���Ұ�g|�|��]Jy��U�w�u��p��L@������uE��?K%���-��ha��[r�"N���D��"��t�{싼 Sc�.���Ӆ$�����=�=��A^�,9���� b�?�z����,��n�Qe|����������o$�}r��{�� �U�n�F|�W � � ���M�F�`* ���y y��M)����#)ɪ����������׷uQ����.q�JFj�'���� �HߓㄽW:�Le÷۔k��FZ�s��Q��g�& g5�#1ߒeܙFgp�������h������[�n��(����2W�����9�_,W�[lT�r�3����rh������,S��J(�1� +��rN6���wV兇i5[W�:VB%��q]�!�7ؙ��rĺc��l�P~�¹/h�_� �v�ƣq|�2Ci���KE: ��>G|탘�X +T`6��@�7 +(����mۈB���y<0�?�on��/��W=�.�9X��Q�3�w��.UJ�QR+����J��Jf*h7���IɆ�{��hPphL��l��� + c�DOΎ�i�Az�w�՜��JQ����y`&�f[)'�:��P�J��RN���6�Ȼ���Jf*�x��#���&g������ݪ�����0�/N4#����i5ڂ5?��A6��ԍ�D�FoT��n�����w_k��$����|AԿ Q��2�(T��s���u�ߴ�0z@B�K���mR/ein�M wv�Ի�,U�^�9p�*Tq8/�,z�o"�e8S�/�3�!��թ#c�$�Ԗ3g�!���� ��6����q��7�4ޞokN=gAĞ��ˣ�*K�J�]͡���t�C�8�7�NC!߾�����t��$��ɯ����E���%�YHz����� .�취 Ρ�7��v�b��i�)&f�'�^V��il�\�o�����**Տ�?*�\�k��L��O��(9�[�owA[rN�ZVC�L��z��h)�@�ʢ� � ���T]c�Y�d(ˁ,_a��$�K�j�����sc%p/���i����ߕU]o�H}�W�H����>�˶4M�h+�bڨO�`_���3ޙ1���;���I�5�̜{�����*�������!�� ����r�H> +K_EQ��cB��Z!)����Y&�,�p�Cf�HrB�7��p�k� +����1j���V�hmPj��5r];mP�!2CT�r6b"_~�\ͯo���ǧҶ8J�H���Ң��;6�@���֢�TmJ? e¤�3����,wЍ"csY����ķ�0�-ܷu;]wTNXwbL�e�o�7�܃���p�ΣK�����cu��R!�eUH����z�����^�g� +��t��r窫(j�&~�P�,�F���7��混��Ed- �SKC)�;��*d"�� ��m��K��H'U6a��#pj�Q�~@i�m� +�;4�Ř�C|���x�������gww��j~cy�����|5_.b,o1[|c�_�ŧ H�� �2LBH֓ғ4�3pV:�lE����PY-2B��d���ȔҲ�B�(d)���e���g�C%��\���a��#�D�tF*���}�ݪ�Eo�˨?�/e��6�QhrR���w��X�-����-yg��H�i}��e�)q��_����L^�����zX< �3���ZYg��Y(j^)��gr�DIaW����F��H� ���8� ��k��;M�5V��.���Yؾ��������Y�R>R +�U�[�w.�w�-�FX8#�C��C�i}^�@�7Nj�Y�@�Uq�E����s���F��^-�k�b���>;�cJ^w� 7�0Y�/�q�#�ߛZ%���C�{;z�ŤjrNp +U��l�)�`�[�!��µ;2r|7�-�;l�� Ճ0F�F-���O��&��oJ���6 ��P��G���d�(���6��c8��v�>hs��, �љ��VCX+3�w�% �N��|��ڊB������Ư����)��uq��YCW"��-�sd=L��c�{obFC�)#P��) Q�MUu�izT��F���ʱ�B�B���m�`����{�T���vP����a��d�����d�eO6f��#_�CG��Eb��.a� �&Ě Jt����R��K)1uM�Q�;,���x������u��sT��Oj�t�v���i����� �����l}�FK�I�l@��wN��������!��pP~ur+ Es�E�����F��6!�ئ���ߥ�]O ̄�<ҁ��Јő��o�އ����/_�ذ�^�l��<�O?O����qJȆ�o_���R������������V�`�+�"D��8�X��g�!1�a�e��P�x�;�gq��.���2�u�ur����T�n�6}�Wl���Yֺ�� ��rWdEa�Ե�E&�K*�3���R�b�Ч=��9��{���olm���$� r-��$lUC��BcCh�����V�8�����Wfg�&�]� r�*I:�����VȚP��� &ܘV��+�1�7c��$��І�3L�F{V��Fsd���hkQ��/V��,*�R�#�J앯�k�7�p�Q�*� ���E!�T .�� �=��j��ĮV6V�JqӋqG⾬78�����u׌ ~'v��yz���#h����h�Cӟ�A_$Y�!��6Jhѝ�o5R�#1/���V�a��]�ݠ��{�:���}*���p�����j6/f���Yy�rL�[�Tbs���QRlB#�a~qLq�Jc��+]M��x9�������qB�i���ݴȋ >�_�W�0].��U>+�X�j1��W�b^`q���> �����51��`�0T�'�/��kY��,I�U��U+*Be�u��%�)� t�F픏�r�o�?��O�)��,�7i/�,�W!Gδ| �[+�C��N�ぐ2tIJz>eɫR1.Q*�bG#��7��l���"�� �����)i��|9�Z-���bv7]NW���e|�$j���>J�j��c��O����бb������pt��i���:�Y�.���g��c$�.�Ϥ)�Y�B�Xf�0��^ ����V� %_jB0��yg���W�$�F�7aIp���R*apoZ�G�F�� +���ò���!l��֦�kH8�6���K_~[�(�l�q� �'��IJO�6Yi$�A0�5I�m�!��嚩R���1�-�N0� �)����� �Zmo7��_1�J6T)M?`׭�ľ��F�(���I�W��JV����ew���K^>��g��p�|�p�ܟM��A�����'��q���?F�1�W�L�PC�0�{` �������/RM�rlL!\�L��p)�s1�:�LĨ@ +$k�`&��Q�Qf���!�(� +�{CD }s7xu c�X��kg�1,����r �a,�8��5K���T3�*�0S��L��O��B��S���(��UpF;�Э�������.��JS�/{/�c�֨�߶�N���-AH���)���Y�p&"k�������A�f � �� ��05&=���E�Y{RM�!���������/{/����֠�+�a��� ��(AH؂��N��~.`���b�%k(P��bȂ�\�4��������v1 ������͇;���������n�ë��׃����n����O�����u��)*��TQR��ĸĦ�q�ϒN1�cA��$c������!E5�&V1$|ƍ��&�Jla���,z$(ZF�����g���M�}�*����ľ8���}��Ǩa�f*c 1vsM1rkf�yp����O��#�/�/+p M%�t��R �O��u�89 M>hT��s=h݋�i �^�.� ���\��ɠ n6;w� ��t��1�64঱|�-�_ ��{�{�pn��Bۚ�P/�:����\���U�{s���.J�;�~ՆvC����v�߭L.d�'�,{"��T.��,�1&]&�O�`��=�8�Y�|��L�Ixַ��ϙAФ��8��Ȓ��� ���G\���^�}��e��ц z� ���M��� ��k4�� ��ǹ�j���+(ƾ���\�ɔ�����J��(�Q�7x�Rl[~�x�����6�mr� G��������Ϸ�]}����~*5� �6�]����t�0�~��W����u��/(���w�r���[f�Q���E��K����>��T�G�̃ ��adڸ�"^)Sl�W � �=�H_uL�N��\� � 1_�y�k/��� T��|��V�fC���0�t�v ����j�"�.�~9k}���ǒ�v�xB�ϕQW{_y\��T|2{��'����n�"�c)�^q��.e����s���C��l�_��"�� +ߚR�5�m�/� ���`qB������;_i'��*��It�NN�43�u�f�"3�|iϮ�=�-@�,�CI>�{2#K%ۦº`㧣x�P����fG���{w�#����Cx�9ꂤc��S_r�W7��ܯ��1��z󍔰�ar�Ⱥ%���bԲAz�VY��6��e��”hH���|>�ifîӴ���fR�6!��ޜu����bʣ)ܾ�%eP����u����9x�T��I ��mQHn�v�t�� ���%�����VZ�XD��ܶeWD�J!�6|��� ��X�8NB�袉����xp� ��n�(�HR� ������Ͱ�~�=s�#�����ް3fV\�h�z�ӉG����:i�:ަ /��8��3h��lo�p�S�j�1����O��w,ڳg�حW�hy,0����]���Rl�~���1V�#��'�V_��t�n��T���%��)�� �V�c���Nn�ڂT�:b��ۋ�7�bΕ��l�3�m�2b��xz�1��rW��.�I�{p%U�n���t�M�}�^&�{`+�`F��5�F�-k -�fK�/�n43M�:A�bށ6�C V�b�Ç�������'��_g�Q�� ,�hw7�nJ��і|�G��bV_��S�tL)�|x�eq�iC�@7��9ua�s>묎L}-@����)�W���;;s[����]]w�YnM��6*Aѩ 9�x��� =�S/�K܂�M��6Fh��P���E��w$� �o��o^3�����ٺ7�LT��.F��*}vc�H��)MdL;� q�f*˿�T��:{��5�6�L�~ߦ��?�Ԋ>�ДG�0E�0c\$K�*6�<�#SV丂�Q���ʛ&b鲠MxWQ6��'�#H��� ��1j�����f�� FX�yբ�(B��ɡ��F�/A#��# +ԩ�&,_�h."�p�F�� !�O|Pt)���0�?K����D�������s��ԗ�3 �6Y�ZO+�l��O�O�#� +/�v$�*S�v!O-C��6�f 3�ж�%���W���N�zrx_s�*�3;R�Ok�0d��N O�V��#5<����������ib�oa�Ɲ��Q+�!��Z�}n e�Fwo�ǝq��3�B�����Q��'�'B��ߍ��"*GA ׆E(�µzS#��Cv�2(���r�_�<�o7���x5��nMvoop�4���ƵI`{7׫Ӏ��$�G�ɱ������c8��\���8c��g�����ɳo�e�(��G����EΥ�Xv��b��å��5�^�Z� +%�����1Բ���[iX)�!W�j1���P:������L.9'�o�^�����(i!��� X ���J��\i`E!�hV��s�W�n�|�t!�rUm�X,-����,E5�BR._d��� +6���$T{f��o\$���'pd�����=8~J�WlRY� o���yeAH�ժ*�9����3&?z jf����P�t0����:ɲ�z=a��D�E(̾??{�����?N��-�%74��Zh^�l��J��Yɡdk����/$���B.Ƹ�H�԰, (Lk���HB��p~yߞ^�_�����wo�z�O/.N�\�����p������o.��k8}�#����7/���]r ���H�� ���H�)����d*���ȡdrQ�����Z��T\��A�`��R��%�2��G����EP��%p�F�[�w��ڪ��-��^�Uk�8/*�� �2��G�z�V���^�T�� M9Y��˂K +n��0(���y-sg[�n2�TYC����|K&�R�E`�*;�c� +�,���R��3s!� ��ڈ[�?���rU����!� +� Ja�V�~sɍF�mGB�eM�n�Y!4ϭ҂�c�Kf�����&��s��yM���ɑ}���I �#8�C���f�#��&�/Fp �O=�-4Qd�b��UHB ^Itx��Vs�N~�������/�o3�K��"7�v�����E�u��6�-ӂ�z����b�8��|�5�9)4�w3�9���`6+�m�i�;���gF��䫏��I������YX���7� �|&$C�#��L��h��Jc�F��<-���Q[0�vj�LȨlj*��o�E� +����,(��k�+��̌![��R����A&�?�܄q*��r���4m�Ҭ�\�� +ɞx-H�3K +����-qo�ʛ�?Ǥ�~+/4���� YA�k��D}1�Z~gq;k�^:��ULH�)���r&a��X�� �0KF���5�� +1'��+K�xfpx�.��-��(g;&���6���gF��� �����K��чI����x�V<���5�i�����#~�cX���1�M�n�a�rZ ,���l�{7"�G��?�!�r��h���F��7����8�2 ���`/ �[�w����q!�� �~MF��������(����y���ܒO�k�p�v�G���XHLm����k��95p~��F�Kxr��'O�x�m����4>��(=�� +f],51�����y�2�>�4!&�������ۋ?^�zwzqz��& �O�媖�믇^�R��ӔP|4��{�����7ƇG��$j�,7�.��Ɛ� +��@b2� +��;�O��\�U�R�K�֒>� e��j09t�*��ڸĘ����&��y&�8&Ї>�'[�ȹ�$�q�Лq!][v�)��Z��)�lc`��X�Ɂ�J�ZH��ƥ�X��,�B!����N�_?<$޲I �7���7qT'�5� t���msșp��� `���6^B \lpxi�Tq1Yp���퀀�F�K�DԱ �ۑ������xVA��(|���6|^�M;i�2:2 e��%F�듎D�����{)���sϲR���<���/� z�����2<�����-�����e�#Լe�!Vw��r��.Y�cU�H%��sE�|�k�A�ߐ.Rz.��(8U�h$�w\�p�V�bF.JZv��A�W�����sK��|��v[, �����uN;��Qgq�u����β���E��ޥ�.5փ���Q�zH�(_G�8g����'�X\�I�=昊�2�w���=����~���3���I3��l��j� +W����vLe�Y��"��V��JO\��t|�鸑���y�nRC���|,�N��fK�B,�����M�(�sDE�����!m�i������)��a��C�a�0�4��u�6�89�xu��MD�u�Ĵ��?p�pX<~��qt ���t +sV�Q�;��SMF��o��Q���� Y']ObjLt�������E����>�_tS���g�š�G�>�'cp)3��=�C����0&Y�9���t��u��+�o+P0���s�i���8H��J���n +��8X�s̤&x:搄�<ąw�UU�CȨk� ��'ۙ�?�0>ֆ��>z�$>���l��"5iUS]AF]0��{a,L�e9?9��w(��!��}׸��g���z���ㆆ����l���]A�w�wXh�m�����6�o7P�9�K +/�.9V�\߇3���Y����z��r��+�ig;��[�VK16�J�"�0L�b�c���-93�~~Z�jR�� SAFr�cHo���G`���#�v ��T��~d�x�(�ʋ?3�����n�� +�S�~��v�#��Op]4>Sp�r��u<�$Qל�cr��r��"��۠���.1�n�LE��B;���wƙ^|�A��Λ��ߌ�6�)Fމ�w�ZeXɇV�Zc��ܷOb��/ڥ���^���6����lv��ӎ��~ͮ�7ro���.8�����Eg�)0�uyh>�ۚ��&�矱1q>' B�Q_fUٍ�:�#84��ρ�4ĝm�mv��ۿ���1j1��2<����ԉ|��E�}hk��sk�#���Å��҃(��B2w��G��,]K�e�lT�c�o���!sO�Ū��B]A� ��gj��+�$V �j���?�CSsx��]L�G�Ԇ{,��/�Fe,l��u/���ݵ.��.$w7�\���6]�:���!�S}���s��ۧ�ڷ������_t�!��o�%:�8�1�tX4tOq�]��@H�o�i=�U��7(����So�p��9Z[��[h�=Z0��G\���_�uܠ�O���? U�g!3��\q��-f��T1u\q�c����]���"���{���D \����7o� m��S���5"�~�{�m����SR*/oD��hVP�)~j���**�$��G.��C=Sզ��=%���n;f\�A|�b�f��st��]D�dr�?�Xեv�T� �x�~2i���J]�D��1]���N�т�n��a�����s]�t��&��Z���|�8�Q)b� b�0��}��縚�@����I�?I�ɒ��(��,�Yw����K[�E��w��]����=H�� ��Q��=�/Kf�ZT�ǐ��q'�����;$g���Y��мdV�,ťWa��5Q|t�/G���$cÉ� ����S�-n�Dk��~_�i>��u4��O+���$']&�ڍ�Skٜ�]ij�#�r�LbN�A"��K�2�t������d4i��b�d����mSiGs���jƚQ]�(�;����"���K����}����Iaq�� Y�_��Jk��(��4~�Ƅ�d?pI; ����������xKY5�4�,H�7��σ���R�hhCd��m;�ѪN����:\��8m��Q�N�{c;j��>���=�)�F)�;l��;Pf)���A�Ū��]�O���&۷�F�a�tjs��QJ#��)�d�`"����pJ�pk�4��5�8��87��c�n}�N +6���-�� �f?���Ν?�Ʋ��i�N�rr��l�zCI=3d�����>6V�\X��O=�L��J �2�0ep۷���&���3��H�>�K�å��7}�C��&�}�gU��H��a9��I#d� _1� p�7�����V�k"x�Xa�"���S#���⩚��na����e3w0� �u-e��S�:���Q5cl/��Re+.����cd�0���v@T[����!�{� ; ����֚��e��W|Vs���fU��_Ѹ�P-�&9�G���F�>�m�Im�;n���b���뿌?�d���(j���Ѿ䙠k���jE:��B�F�,�ڌNz���'Lj�/�]___�Z��`u�⬛�S������亷���?�t��?>��a/� ۇ9w�ıw�-��*����]�|M�R�Gȵ�!�����ه�]�'w#�n���^��� Y� �y�9���e�wZ�X*�e� +�$,?=�@c��;U��)�������G�}����Xmo�D��_1�*%�B����!�"Zt�q:!Tm�c{�f�쮓�P�;�}q��\��RǞ��g^����UY�&��=8�!�V� %T�D�O�;fq��.���x�Ge1���b�DX��m�A�ѵʘZ�`��B�24���6��&�fĪvڀ �q���1�ћ���_̯!��g�=�`+\ ���,��{f���n��K�{�������%�����#i����~(\��2BO�ZՔ|�Z�Y�r� ���fB�7h|#Th��Rb-0��k�|IYR=��z�ۊ�G2E-�lb}L&�v�@�X1��W���y�>W}=8���������5�R���+� 2�l�%�`R| +]�sЫ?����?�R V,%��'_ۜ��eΤ\1�h�@�U.�ڄh UHtZ]�cX(��RC���V� +)�d�&J� +L+�-�u�(�aB�sR3��2�ΐ��I N���M�9:^ν��!���DJ��J�'F�1"�p�ᕿ�D +�P�+)8X�y���f�Y��+�&��a�>�Z�X��tz&�, a� ���.A���c�}�L��`x��=�����㎑�����й��s�1�j��%���y�5I��_S���Td��^`[ +^6���Pz2�{�@*�Lw���Ң�G��Vƞ�rk����Ⱥ�*�nH�q0���P9� 4���@��}�G_~��N"z-o'�<��M��imњJ���w��eЀPM�8�b�3̅B Z�� +1SS��Tw���1�TJ��Ro�^ؚ���׵�`��֍��Ѿص���w$�H �9h�t�ϋxDOܗWD�6�=}�, �a����0c�n����=�>\^�3��n���滜bml��MԚ�&F�����J�d\5�Ɩ�����e~k���֕V��A�C��ur��(�O�Dȇ�b|Oz��Ԣ��z,?��:'�ha��lK41V �P@��#6{���ȯ.����H��V���ɚ�l:�� 31Ǵu���*�F�I�]�Fl�C8K�f\F��Eo�,��c��y�Z�O4�B}�r�}� [C�-xB����C�é�3Fǰ���$7s����w�$��{f�Xl�t u���J��i���J������8�^=����}?�빹Ci�;� �K���V�ޖ��͸���;�;�>8_D7�\m�N�^�:E� ƣ�{:ƺ~� �Bm�ټm��#)��X~����F���4��Gb"�C"�W�J�zx1��%`�U����E�|�4�_@j�RY�Ԫ�����v�.��}>n�y��� +i�gI#�zrM��tF��I�|2G��,�BZd�բk����������[�ؼ��� �‡�o�.�f9$Aa-���t���T��k溕���Cm�<�AZq�1Mo#�ð�W�3(��V�{o�z�T]��6|ׯ�pg�V�Ǧh�\Ψ��NN�<��J�E�$u�K��^��l� +��/�ŝ���,��:W��E�6� Қ(ذi;}��E�[kn/"[S�,4%�E2�#K2���ص�#Զ������� �^כ F��5��֣��(��a��C!ZOԓ�a�D�~��W�whXg��pđ�ȱC�8`����Jq���`�X�g! �^���uϞ�.Ž�|�ح�}j���b‘x�l�x����E��0���|H-�^��u�2�j:��y�ѽx��C�3;�I��`i{�Y��Sw�o��/�=$� r+��eD����we9��Jd�+��r��X��m�o_�^M�OFS�������i�� Z�ɿlS�� FϑM�L�0G�Ҥ��f��R` Dv�j]����~]W������O{|^�߯��������j_��5v��_�j�a �ؑ=9�����I�"M����ɥ�Hr�Z�v-�����n8�=�dl�0 +�{�9Ri���j��;'�C�J[�_�_������_�����w�݇���w�[�w_�[���q�Ɂ�:'"��<��J�܃der�w����2U�*Be�ŕ�ȵ��XeJ4�r���}�mޑw��_�J�)g��[�_�Kp���ϋ��F�LNj�5�� A����()����T�a� 9�T3�A^��BmK��p� /��^r�M�R8��PF�k%���&OalD�*~$3��:���w�r��M/��G��i���ذ�\g}1��C$Y|G����$y�K��Uю�6|�W bW+�c�M�\Ψ��.NN�<kj-��H�\��-��iɧ�����m�;�ٙ]����.�g� 3,u�P�i�M���zG�et�5 m���gHe�b���T�p�jFa�r �X�Δ$�L�r�Δ�aM��h�?�����ќA�gn�H�s�_o���;�u��KNu\⠥��:�`�W����WSm�ַ�H,�\�/�Ne���؃aj���6J)��p����z)#�}3��[�5x5��ԩ���jz��[:�XA� ��� ����k4���A���9����(I�ݏ���7 +�E�y~8��έ��Aa�au{�.�5ٗ|4 ��t�s���\�UJBC��_�)ٯ ^�6�u�C�&=�l �ÿXJ]- +��+�[���V۟7�����_�����{�n��W��f]`��b�9V��Z��k�ك��"�����r���C�J�Rp��^+4d��*Feا�p�[��dJ4�Ւ"b酶y�Ƿ����)=x���ԉ���yz>d��[�\�2��a��1a���}�e��h�!5������5i�#:�O��ctS*"P�$��f�;+I*���S��I��?[�gO/�Q�WIb|���*k��N�e�; {�e�����T�8cA��ڞe���$�ڐ�G`���v�i*K!$<��e�m9@���u�F+�;��*���Lr2�ɾUq��������s�Es@�'Ǥ�#�()��s�nJ~��[!o}ByO�I�:S���Տ\N�%\��]�]�Ƒ8��ERע ��y��+*e��H�[G�����s�2=;qY��M�w��u��V]o�6}��83 +�\;�Ӑ,i�|��R'��u�KAIW��H*�7���$�n��zH���{��oo�4�;8�5�PI˸�2�M �o���@�]2� +f̰op�C��"X�/�s����m�4�Z2b�+��xv�G!#�P����Ȕ�"jVi��#X��2�� ��w?��O.�s��#n*;�Pr�¦ܠT���`Q�]h&�e�t�q���#Wa���Ij�JIڤ<sW��I�T���Va������k0���q%�г�7�֧������RY�V�A_B�-�D��\p&Co]W��1>�NT���@����lM�Z���FeY��w�t2j*�L.������ã��A +2��)���,�Y ���?O���K��[.���6M �����I��� J�y���&�.ލg��'���s|�ߏ���� �����^N��� ��O?9��'���۔4�K�]J�;<)Z�&�+5K&���<�`2)XBH�i/��tƍ#ր��g���2�t��F#os>:WNF����?F#VX���,��Q���g�{����Ѷ�^��CQi %[�41�0uU�),P��%qi,�"��…�r%+uN,�* ʔ<�V�]M���;�9��pFP�HP�??�8w���('�%�$RUnFq}��ᇀ���z�I�Ck�u�����}����,��)���)����F B�4�Ȓƫ:�dS������9�"���ML�E��ڡȬ?�����zعA�� �����G�%�t��_�Č�n҉re  1N�D�#Cܢ���R�Eh=������V&��;#�?/�Cą }G}���k����77�{Ê +�m�j���Ym��}rҰvr���������e��1Oخ�˔��c"Z���)� Sl��_�X����i��20!N6�|mn�>���AR��ye|ﯜny4���Asb��"��/Q� +a�C�T�rW����_u\���M�HY��&��.�{s�ک���|O���� �̉�����0��S ���m7�S0����ѯ���q�)T��;4T���UMB��O����FjW�>�6;݃ ����vY~EdB���[� ֯�J7����eh� ��:��41&�l�Ӭ�WaSǔe���Z�L�5�����aJ�ٱ� 4���2����Yi�9�gK��۵|�� ��lܕ\�����CO�k�<��k� (dn� ��2k�1��H�=1.ܫ��-V��w9�f�!��^��Q���r�L8< �;�j������ab�r�'+�����ڗ����6؜aa�DU��Oz�(�DC���ӓV3�sEh�T6���򍃒 fr�`�����i����!�9g>���|��|)�Q�o��F����ۡ����A�z='������dR%�� ~�Q��=��:OE�m�֠4��ԏ������~�w��� S..M�� 7~���[�B�ď��Kp(B }h���r����8�"���]��BzppRFȓ�ƙyy����S� 5y�߃]�5�31H���Ki� �z=������{��<��8�u��ڀJ����w��i����x�%%$>#�����6y�$�n=ۄ��yv/�μ��/r��d�RV1�m�_"4…�6����1����>�+{Rz���~٥����I�0]jnX��n��s��;{Q�2}�ӮqR\|р̿q����F�RA�\�[�m�m?lK�~�9K܋������#�:攬�Mi��p�&��uy���ʙ6��M��hm��u�)�, �GڍSh��Yw9�L�J���k�M��Y6� FmW�=�uC(�;�c5,���F(���5Y�d���&�t�?͞�g+�2¶d�oL��Yw����e��&�nH�6dz�'��~@��~]%���y��F��e�� |�n5ێ덭��e�5}'�P*B?�灋��֨�q���?V䣕lWS�W�����]#�[�[��i�?�Wmo�6��_q ��)ȧ��ӺyA��N�k��0����J�I�����%�v^�.�&�`�^�{�;R���Ӽ���`�'��0�s0)��EM���)���!�W�1)�8j��Y_�����t����`,�@Ep. �aR@g0>�B!�)�ZK�Tex�f�� +x�p��2Fc"�~t9��A¸���.�(�3)��iXH�����ȁ�D��%b �Q�n$�b�Ԁ\R:ey0�P��U2�t\�5���P�}1��wR�B> +�cRg��Ww�=g���4PhZy��(7�D2�9C9k���|�N��R蠀L���' + 5&���"@�o �<��Ó�����(8�&'�A�_S�l ��E8��?G��� X(f���[k]I�IҪdU�L�m��1�3�p�o��x> '�.?N����j0� ��py'����dx9��9 F_��o���>3))��\YR������*�ϒ�)b ����8'��kR�3rRӖX (b�,c�IJ[�-lU���1�n]ٞr?\{}�!F�I���[����l=���U���e�R�� \j+��L�Z��N���8HLh��Sl=�p"�\��CJb�������gȄKҥ^���8j��p��'�,�.�E�--�x����쳍����-O|P�{s� +Ʈd�3~V�/����5�ݛ��Z[�(BC��q#T����8ɜ�n�p`spI�A�g$��7�i$�6��L��v���Ϯ5��!fʾu`:=^�M�Ѕ�a��f��&���ʏL�7�>hW���O��xjCt������+2��+�mËy�x ��KkVX��:T�nt�Vw;G���G�ю+�ťx��M������[��o��B{W��W�Q��c��ceA����&"����t�ج�����T�?w�<��O�ĕO�C��L9b���q��d��ݻQ���꫉nG�0U�Ü�I-��/�I7L �Eh]�ܟ���UI^#�����W������1]�X����ոJJ�� +W��՛4�I�"�R�x{԰[��n�k�>,�N�(��k��r���w�z��������mk��oN�k����/95K��JU�vgS�؆$�v��ZR��7j�����}�K�R��� +�3m,��j�����<��D�auxW����Sb���,��0X �F{���$���5@�p )j��wZ� ��z�}w棆k�E9�+g�Ľ�W)04>�Q�SkQ�� ;�^����� �{"�n4E~��L"b����/s�� uu�B�I���Cc��[���}���A� +R[������ ���>,��9�T�b�:]�ӱ��.�;P�l��"�n͂��9�."��㪄˦� +,$Jf�}m_���m/��G�~��'�}�� ��˗�:�j�xW�vz��*�<|Hկk9�W_�RV>����!|�� ���q���V�+%'9f�����6�5� +,���������%�ߠߨu���&N�5�-�u��^���Qm �^���zH�[GN#���m��q�_�Xmo�6��_q˂!R���eN�Ig�u��m�E@K'��Lj$G+�߇#)Y����M������y���y�d���a ᜧ��q�E &A����L�Ef���i�i����(4�`����X� �ddfL!��\���?:oC.BT ��T0��T|�� u�� +q����Ѫ^��g��ʇ\;9 a�M&�fR�@$�0�d���E$����L��` �B�81 g�Nx��+���0�).� �̽+5�}0��*M.?�<��X�=���>��SV��r�s�wf��@N��3Xi�]e���+� �udT��x�c�����l�a����n�a����l8:{��ԋ�)j +�̹�&�,Ky�&)B�f�������7\�G$�K +�A���< � �f��`0ڃ���`tW����pտ��ǃ�\\�����`<�����Ï$��`�����]�� ��S<1���<qţ�3 x�H��s#���ͅ Քkm���R>��RJ��oe���XpC�(�����.ˍ�Qw�v������ľv[en�y��,vY����[�Ia�m�sw[l��b��5�b��J���� *f�j}i؃�w��QD%$2 md3%3T������/n�F��L"�L��m��k�ϔ4��皎[+lk�����*fr��Sn+�c��9 !Rr +Lx1w*J�#���c�K% U��bJ%*`iZ@ƴ+<1�EQ��W��k�� S4�� ���ʴ�Dž�X���x�D�Y��;�b(���g� �b���� � +�$0�"I +�;� +SbTt�����7Hni��g��j�� �8�D�sSl�~�/�FA���z(5V�z�䓔�"��]_WPx,+�=o� �g���ER! 8�of��z'��5�.�ƨ\,�l�N öZ��"O�m-��R�J�m�;���b�J~�S����jX.�>4X�/���� ���]�x+o-gL�)Y��㞝 �;�]� ��y�|N.�H#���z�����dx��v�v����Р�Ƞ��E�t��E��Mu�{�?%�%��G��^��woPX��{|�z=W&~�i�C�R�[.��P��7�du��o=?i� �T]o�0}ϯ8�xت�L{t[+"�-Ӟ&7�M����v�����$� B�%J|Ϲ���y�+%�I� \r%�`ɲ���5?�2g���B��$-p*ʹ�+B�����P�,�c%�?�heAJ�G+�F�>��M�A�3B���!�l dD�~�Z�'sl���m��� +�b�N�l��( +��E �[e� � ���Y���pY9�N���X{+�bc{�1�Sةv����P�)>����Q|�}W��p�w�:���T��v�]Nځ%r�蚅�zp�#G \ $j��@m�A��Q@�~�$]��"荕)��ar��̗���Q|8@.dM��З� �� ��9��P���/�)��%:Îe9�h;���&=�l��I���C{� i���Y�fS\����5.g���:�gX��d�4J`�֦ �xGC9��*tuo8/�F��W#��/%��dl �: ���J٫�k��"c}�/G�wEp:�'�����{P�Am�h+�r� +�.+ɨD����|�@�ʓJ�޿�:� +�WI�4�C�#m�$V�|�^��қ/G��g%�Z0�O͆2X�V�d�+I �������1�X�C�m��IzhYL��� Z�N�)L�x7N���L��e|{;�-�7)�o�z>{?]L��Ͼz�?���C v�me|��~R������Jǒ�H�HTy�9A�7d�LTdJ��X �2�\� ����ImqF�V(�<���p����$X;��r�'I0E��>[�R_Γ^��ԙZ8h +d�f�M��BKIµt{c�e��Lh��=��`�G�I/l��� m�lgn�����B�w&T�u^�!���o7h����W���% �U��,��d�c^��Pu����!X���B��Guڡl�j�;yx�큅�_��%��x�Z+:gAQ�\��^aŎQ�e(}�B���^>4��+��~��s=VĺV"�o�1��C ���8\�Ű���%���N�F}q������);0w1�>{��'ݾ%W[��:���]̶}1Vx��i��4�w���4��6�d�_���=����Ym�W�m�Y�TX���U�zpq���֡#(�.�{ݼn+m\���� �e{a����I�AG��h�@��PKr�Π)H���*46>�>|� =^^���lеlw�^���#!��Y��!�6bd�Pq]��G��y�}�x�m�; ��?�r;��(���7W��V�o�6����m�V֏��M�X`��. +�L�%"��To��>��3��-��ݻ��_?�Yي��t��L +�\p�����5ͨ����W\�?�-pQ7��Д��.bX"�b�25*�kY� ������HH�d���B*���2RA�3��� at &r�'���r+����kG ��d`2����VR& �И+� +W� T��J,M&˵�if@ւ��x��[*�u(F���HX˪��úiF~'�-���sh���4wO:]t�k�@�i��Qi� `�(s������p�$�K+��r�{ �4BdƔ����>�z�R�Q`݌/G�x��}�� �&r��]qE ,׀e�s�˜ ����dr�s�↋�g�u���Hۖ���; �S�d�8>�/�x���x�u�m߇��p2�b���r:����I �kN�l�o��U����c�, ���~R��P��J��.��g��H+L R�@�MDI��� +�E9/�q��6�[���%�{��Β����#��22%a0�"w+���j��t�V��ب��3�2Hh�i@P���p��Pz�b9j���z4$��_O�����~�{ �ԡ�H��^i��.eQJa��~�$r�L +m`~w;Z�'��l2���l��+^�UҮ4��I�5أ?6ؿc�]sj֥�)(������\h�6�v���p=�!��T`gJ�{%��2�̃=]G�v��UΤX񴲓��PK�t�&�8k�\b����)�觱.m��٬��/��vߊ�%q{גp��|Znl*wt�J9�Q�¢!�!����� �TCV�`X�@��{���D�q)�@�ϩ�ػ ׉A����M+�j�C�e�<mF�R"(���f:���� ���U���_ /:0Ϸ�KR��͚{JB��}� :\<`^Q�q��dڠ!(�>�L4��ʸ���jᯅ4;��HI�BC�L����;.��x>O��fs��M�'��l�������������5*��R� H�'����Z�;�K���g �,*V �JZ���6\��j`2�7�8Qik�,��J>���OAHS��<��P�Ұb4r_Y%i�T-��%�~�8+y��@����۽��Y�܍�"'y��?���!�[��?��<�|�?VEe�;��g @7��=�D�"| �,�ͱ�ڠ���/������C�����v��{b�EHZ�0�bWb[t�R�+���3A�xI*��[�Rf�)&� ��ʘ�M��C�Hki��m0�T��2 � +�*��!��AtsM� i7�CO$���lR� |D�֧:Qsԕ81(IiU�*�0B����򍮯��Q���{ _�Ч���K�9ʬ��c�=B��c&*;9^"�q���EݱB;�eq�D�U�1�5�Uk���Xp�} +�JR�,D������ �@�}�׸b��,�yVD^#�Z��M��3�]��y m�5�xJ�QUf�#VU�w�r�Щn�T�ֽ�/����nV�X�'��7����{�-t8_���I�(�Mm�����(���$��/Y?���{=������t�'�/�᎕e�*����M�C�98墳 �9���K� .e�b(�r�|.���.݌�, �=���0���XKo#7��W� +>HY +r���8�+�D,��faP���-�C�-+��E���`O��<��bU}_=�.�m6��{7�w���q��������2şP�7��rQʴ��J}� +�1i%�2m�21{�>�\��p)`t��8�\Ĩ@ +$i�`'�;V�un���i�Q�;FO��V��n5�����V>���a {n�`�\�^�GH�ǜ�f)p�H������ S1����fk@�*���`E�,?c�S�52��T�����T�\�~���� + ��p��J���4�k,�>G��"��R�Dd��w�S�_��&ȀYW@&�m�� +`kLv6����)��N��̂��O���������w^�HQkP�{�ư>˲�Gl�"�lO�Y�,�\�^q��fB�:P� +R�` ׵ R� ��0_�ǫ�|9�_櫿�}^�/W��W���v w�p}�����w�%�}��ů$����f���s�� ��S<1��)�@\�(� #��R&69� l�*����&bH��K)M�-�B�|�X�H�|.��L�ć'ϓٌ�FnP����RH���v��V%L�\YF�!�iM8�أ O�QA���B���P����8+I�����<�:K�A�����#�+ 5��e"v�!B���R{L1"e!���kܲ'.s�8^9_C� ���ІdB�_?�\w��8)��<�����vh�2�6Ѱ�+4�s��ӫ?�$����L{5�H^�H~��� +M�a\�-��E8�Ic�LK��kDJ_�"9�>�T2�Q:��bn��ͨ�� + o,�9��� �����I�c�!bi�^��&�k�Y��nS�ڕ)_=^�C%MEX�(�6hz�ē��������!l��1�G�d�4i\;���7a��d? m?��~D*�����j;b3����`�m���7�$���� ��Z@3�&B8��� +*/��yz�r�k���-F�6�*9\{b<��B_�T:M57js��Z�WR#̩��{�ru3_x��^��8�9NТ7w� ��(L.n� ���k� �^���obXr.� +Y�-�^��bF�Ӌ �[?(���4�<�&�Fz��2=�).L2��B�K�^�;��(wIk�~�C�WkD�sgR� �ȸ�~E�i��#��L$� k����oR:r�Oz�|���$��yV�g��_8�Q��QG���J�*�����?qT�5>�w�V�C����T +д�@,�Z�uz(����T�X�B�eb�v,.�qNY1窬3��w +W��cf�wQ}EQxJE�N�żc#��zDxĬ�P�:���MpNj<}]�_�(>,E��AY�~d��B��[�殊U�@��ھ%���Πm�׵Â���)(,�F}7�|�ͫ���K(� ����)k�tv}{�|x��>smtC�����?-�ݼ�gM翺jVm�8 +Z˭W�Boa�G�o�� :� +9!uq?������+L��x�z��M�!�ZM��S7���T��b��(5�HSݢ��&m����;���d�4��$g��j�`�<4�[���=~l�d{��mH/��%�;��WS�p��.-��pI�}*�X=�UsȰcm����w,^�N �~/�/k���}���O�_L���������Bc��Դ������D#\-B���i��kzJq�k�����5j;H�_�[k�k��?�[F������b��YYo9~��� X +di0�Nl�c;Xa3r�R��Au��\���mY��/�G�j�� �i��G�u�꫋���!��0.�X�I���R +-S�w��p)�8K� +��i=:K��G(4�`����X� ���l�B� s3������r�)�����TN���H��l��(��-���|ry K�Z��kG�1l�I�$\�F�XJ,�9�f)p��jm!B�+�b:j$���Ā�T:��`NG�}�h�8�5�2�G���cw�4���O�7�%����୥^�-i �Xr|�03�Dr�����R��2F_=� ��G��nf��c���x�ٌ��w$�jN8�8���ή���I>����\a �-�,Ky�)B�6�?�&�~.`���b5$j PuRi�� ׵ R��]�`2��/��l_&��|�×��ۋ�|r=��[���^M擛� n>���+Q�k2�r��|�B*�dO�+h +:V��t�_�R&V9[!��#*�5��X LĐ�57R�H[g 1�>c����4�2��=N�c��Ba�j<�K! ^ﵗPhY��̕E�� 5�ɏL?M�B���>�����.s��F�PY�)w�D�kT�J�vg��\+.�܌G� �k)�-��A� [C�zW.�6Lڒ)!��=��$������'�����hq��_!��(���G.s�"�<(��K.|�B +K�o�S.:��Mf���`�Hp4Jf��v�8�Y��� ���d�.�7ֵp�\�`����?�0�:K�6������A���X�� _�����8 Qz +�*�yj�˰���)X�'������)i0��r��޶�~r��w�dJ�mˬ �S�����~����5��:��D!nJz�&W%o-_�<�e."���H +mT�~��C8�&�%0�ҾH:�Du|�pX�m�(��,O=�s �=��pR�:��-��Z�h�˪�CZ���#Ky�c�0�d�X��i`�Boa�(@a���K�$��<�rn����SYg�-�u$y.�LwH�0]*�"I4��\�0�B�J��6cz6pXPxe���)�5l����/k'�����Ldn�H[ ��»Mv �.}�g��������h^��2_B��"w �]�~z��y�%G�e�z~1��"�ʕ]�<�)$okg�a��,���� ��(���:+�,7z��7�$�!pT���F��&@8'>�<�z��Չ�5��Q�Q������Oi�늜J���F�_�XH�'4�H������j2�G~w9��xv|�2@�aw T���C��~����kP�W��3�OF%��ȍ��+�Tu�zЃQk��23R�>���V�^0"��ʸK�bK%JC(�$zɟ����� ��*�����ʹﻘ�?�_�0����Q���`�U5��@QY�`Τ�|�n�� `����)D +԰f1���1+��\�!WiBGp�4v�g�� ���c�/�@m���K1����vmym��܉ug�״ \e��jڢ �9I�T�C�$�����Ѱ�*䑽79�ղU����LbйvЕQ?��2J���u{�(�_��@2��~ �l�&�E�������C��t\��P 4S�F�?����Њ:7���l�(�(i�JH�{�>Vh� Mv�������'��n C��ܳu7�Q�$�����]SFmVy�i�c�E +}�.������\A�\H�ҏ9���I�������Z��j�Q��p'u����J���W�T�`:l� [��&J`7�ۘ��� >ie2����yA.�^T�b��*J�V��Vj �D��Mչ�\߻.�u���D{o� �X=�U��p�ڠ[d��Ef��z;�T�tx�[o +���]v�����'��G���Qg��ׅ��i;�/��� +�*5�5 ��-\ӈ��Ԗ⪨��{��nW�m �w�]���� ��!�������࿽Y�o7���bN +�P���Sױqƥr`) � 0��ъ���#��uA��� �}i�G���DY���2�|S�����hGp!s�D+'��*�B��&gZY����wR�:{�KQ���e*�6�����X�{������,�� +a��n# ….U*�� +N��P� h�ĭ ���fy[���K��5*g�sD?�Z\���R�̟J��0��t+p+ia��,����T��Zj�fC��`&LJn'�����BcW�,ȕ�E4�z�Q�Ӱ�ep��u�>�����_����i�O�{-�����b-�!�T��u�K���U:�!��R�]�l��p�MV�Ǔ�f� 6x�M6�.N�_�����?�:�%�|T9Z �SJ�)�nAE.q�#�bC�DqH#�Tو�m,�f��E�mh�s4<���|���/�#�|�����|>��>�-.��pu gW�w��˫��.�t�q��r�n(� + �Ca� m@RD1m�S���%���ȥL *+E���{4�#����Z B��˵t\T�Xw|�]��� +ݵ�:g����R&Q:��r"�L�Ul����:d�TbV��kj2�PZ��x�9����#�X`�Q��Q����hG��R*L�4(.�0�=Mr +� 4n;�v3h�܍��{��b#�ҢQ�$+L�0��B�/�pkA/�)�*a�؎�슡M��[�y��j0,��9Z�7x� �wL�h\�Go"��z�A�#�u�c�� +m��ͷ �� �vv5�t~��9"�r�G��#X��e�4�-CDI� ��B"ju��Nb�MUZLDZ�_P�\~�'$ȇ�N�z�Cy�٨�U��i��2�C/��Wu���p�m@vp���>��I���o�� �L��0�aB�������`}Ƽ���u�8�4!ā�hT�� �:��@`1_�3��O]�� +�) +7O�.B�a�������d�ˆ5:4�CN��,_��2kh2_� �-!��K��^��rd�ʑ��`*� �8��I���؀�Xe��C>�0-�\l +m�z��I�"JG���w��� +tᗣ|[��G��9��A6���ㅤ�䵡Z��`�-.i ��2�n�S֬�%P��[�*��_/�:`� �G�٧m�fЕF���i����\&�,U�{�� ��)w��δ��֩ﮖ5Ӟ��C���j�W4X~~] �V���t ����Cװ���gO�}���96�юU���7Z�&�^����Tݵ��)��O(� �� �{Lc�u�y�u�r��G����R��O� �Ew��֗��� �� +X�[1)�i��A���S��n�E�h4 +G�F���\/"���{�\ %�2n��?K�P��/�P��N�0�O?u{�S�~��-���6[j>m�_v#]����6�'�7�v��rܢj�a�q��ӆ�'O����q�eQ�L&!R[d��^=A�I't��}�0 ��fn�����Vt|�t������ZS���+ �Cjo�$2�+S� �62�i�%+mQQ15Gn5P��nU��O�����]3����J������P���˷6���C�#�VaRh���鸎�w�`��h޿�k�}�="�r>�<�x{��z�!8 ���B �+�a"����� +��A�6p}�E�CK�����p+�7|�MX�vδ�{�s�ⓑ���0�|�[���U� �$��2S����x,�<����0<8�3ɗ���]8���OOEj��'k�n���Ek��׾8����v�@}ܯ&�l��@��D�|�ҫ�m�FѪI]�m�*����)�Q7��2�GoO5�&���$�;�B��xh��ΐ��m��W�����}�� ٔaw0��&~n ��� ^��{l� �˴D���,Qs4��5�k�=�q��`����Y��������d��������2ܷMxj�Б��'g��m�������nKKW�#��?I��ԁ/��8���]���7� ����� n=r�o^��X�o���_q��*�(T��\��VQ#�5$QUUְ{�^f�3�`��:�`_��4�HÞ�����^��3������ !��0.�X�Y#���Zf����R��,��k�e���,� 3RA�1�����������r��25;�nd!F�{5��A!T �T���Y��� �l�7(�����l1�C�3˟p��0�7k0k�a'�=�RKN�Y\�Rm�!Ĩp�TB��2�+�Z�;�J�y>X�+�`�v��Z#a/ �J�k�>|D���?B׬-S�F���{�� ��Bc)�!���M�q&b���;����%e�udZ%f���kc���p�� �5x �j\��\����? ~ <D�Z�¿ +�0��X�g䊜� +8E� +�� ��'�c�SC�Ī`+��ܢ�����pM���D�pcA����[��79��I�/�����x��HYa� +�a���> +���i;�C+� �e�,�����M�ܺ�� ����e��B]dƶXz�u}��o2.�Ov�G��?16��%���`ŷ(��� ��S.0!��� ����Q2Ge���b{x�����P>+c��ޡrF��6�x�`ʊ��%�u?:�|\2Ax��e$]�����M?�ow��t ]��R=[»٧���0~x�~|;��r@z�X��t��$ہ���!�,~�u�]����)|��2�r���\I�1����`�H���xT�<��W���/i|�#�}� +D�e����� Dc�����{/[�]+�!p��@b�R�� +���}حy���m�N��I�%�L��WhTe� +_K�~�t+E��$��Ж̓\�-O��!�Z�e��>$�+� ZG� d��m�� g�mР�� ���� p��N����Dj��C�EV�P,1��G��7 Z�Vdi��w/�^��jè�p[Aض��n���U�뚀z��G3H=���hRG|(y�B �J��+�Xf<���ڻ;˫��t۾�K;G��j&�����χ2|A1��U%B����M�Ra��"��P1�>�j��Cw�Zm҅9ZVo�������ۈ���ϴ���b�[ �h�k)eF�Y���;���7�u�4x \ܹN�G�{*� R�[Ȃ��ܧ���Q���f��vXKw0��JzCպ�P���!���8�r�ϋ����,����O���P>�FE���M�7r����"*����5�x�O︉פ�U6�d�Lc���qY��X��2��sT�_>%Ӯ;�efrwF�����֌�9D�qH�@!�]Pةr��ª�2kf`dz��V�u��}y@�r02H�"�1��5%���IcǩƂ �e��o�:`� ���5��rk�s4�&eao+|&,u ��fH�0-�4��iN����]���N�e��串���G� ��YS�栫WNx-��#S�p&>���Y��Y�i'�?=�����pf��pTnND䈣G�4�#rdO�"Jw�� �3n�J/�>�'w����&<5z�lX�œ��N�m�����r7&��5�v}�t{��t9N������ى�m�����w����m5�[���N������X�oG��_1/���(��h'�c�EM!5$QUU�r7[���=cR��fv��l�EJl���~��~z[,����'p-s�D+'��*�D��ɥVV��[��I��K���WQRe�E.Sᴁ$��[��>����f-�H�S�pka�u�RA���bz݅R�h@+$im`��w��yI�s�DfW���LY�x2]^�B�,�J��0��tKpKia��,����L��Zh�bGH�`&LJ�'���-�Bc����(��ut�z�ѬӰ�ee+ꐌ|Fc)��o��-Y�N��3�^� (���Xk|H�p $zU�R���Ct��>��A��SAp(���@8��K���`�^�;��&�F�W����?��D�O*Gk��ߥ4��|�(r��y���5U� �� +�F:��I���2�I�.J۸��Q�b +�i~����=�2���i_.nn.Ƴ��&7p9��F��&�p1��$����[�|( � H�(�[x�>ZB�l��\�r��Rd��G�}R�YIK�� T +�\IǠ�$�[�w�H�HU谙�9K��H D�t�ʉl0���^��p�* bV��15hE:��m*�J��ad�e�����r�Ì0{ߔ�q"�y�Ku�$�<������ ��-��=Fs 2!�u ��#XS\H�) �h{�"q�ryǵ{���sL��*�GH5i��D������R2�>s�]-�.иMdX��P �ܠ+O��*�uH��� ć &(�1�٨s�)���J�dIa��&Zݣq5MGA'L�L���q��^�G>�\�;�9g�:� ?%:�s�3>���O�t6h;0<�Φ�k�(�>Q�'?t˼�'�StٓA�ʗ%Q*śhc�ZΏ8�j�Ȅ�k44<�<�+T�*�N�Y�F�����i��7|^�U$W� +��SA��5K��2E��cI�W�JC-#l�B�H�� (f'/q�A��.��m�����JW�S8Jq!��55������r� +�7kf��P�����d���fv;����8��6���a����~�����tn��U�W�h�ke5B��lc?�������ڨ�� �8Xs+�o��:�# ��Jw����Kȗ�i�2��U�d%��hͪ����Ƌ��U � +��Aƻ�|�1\�(��z$�@."A�ս�����֟$�1��'���i�XHOe�0 ������߅����ʬdQ��D�ˇ���eq\�-�\@}8�݆ヒ������#+�7U�'��;���E�ތ �����OOVpq<+�/4�����ǟy�����z��'^iqKC� +�&? ���v���_J�2��� uO� {���E��P���;-Ћ'��ﯱ(j{҂.�e�*ۚ&2S���z{�!����nJw���Fɞ���J�}T3!H{�gža戅�����V��ʻ��Ծk��J�PG=~KG6�5�]=��%��w�5��l�����j�=o� �X]o�}ׯ� +A!���1����@�r���(�B�Vl(rKr%����%w�+Ɏ{S�sf8sΙ!���嫼3|��/�FH�D+�B ��[��K�������Z] �:����?�):m �h��>�O"!e)�}����T/� ��.T� zӛ3(TJ�"���ڔ��(8�,#f�hM����ȇ���Ɨװ���–~��V�������#,�LS�[���ڬ}"�h(C�r��wFd+z��ؕ�3.ez��eอӰ�E(e��F>��\���+蹕w����[��(���TG�O(w $z�K�*�ޡ�j��o!�^0�����}3@���`�\�f8�n�� �Ɇ���O�������׃W��%�Z0�W! ���� .$��-3�� +�F8��>{�(�}�j�b��6 ��u/�0�v����xڇ_dzn���ww���z +�wpy;��Ʒ�)�����7��q<�� �"t�.B�(�{z�9�ZO6�D,EUV`F�� �%9���L�T)H�΋ʲ�Am�K��|�P��fZK��~�2b�tF�a6����O�c:�!YbV�kj؉��78l�g4N �o͂G�A/���q��{��Ŏ#��%+F!!�ul(+$V� �Q�π�cX���q;`�� ^��U�D�pÇVr4��$��<�dJ��:KA�6 ��"�t��|-�)�)-����r�ϼ]A ��4�P��*�30d�(� ;%��9�Y��@=�Qw>u:��^��e)�l�K��~�����TG�ܳ`0��s�%��/�*��c'�� ,tat���_/�ZKgor�4��A�� +%BZ +�4�>�'N}خD���3w}IP� �� +e`��1�{� ��8�!� +���`]X ��Ɠ�� +�x�ϖ������H�A���%��V,�,�J��3[���� �hp��1��n�UDc�rmv��~��!W-Ҧ��� , �x���D+�L��^�O��?� +�R��*��������r}�6�Ř��Á�|ʖ��A���,l �NX;?(+���G���3�P���Z�z���R|�Ho�ڮ �XB�8��� 6M;��lZP5*Y��x�&}.&tM�M�t�-ڣ����k��VH �q�R(��Xr_��҃-רD^Ht���]��"�_}������aǧ� s�w )���� ��AۇY +^��8�j.qW?8�>+��Q�JE�î�I|$�cW��� +f�c ܠ����6�e�������L�m��^����ƁO��y8��z'�|]��Ss��.�� ��'�;0�)`�����^�,�g�k�#tf\8!���Z��(�ڧ�{�2z��Iߣ���D;�����4��,��' βí2U[ ��%�s�҆eo>�ȟa��o����\X{��3ۮ�����DZF�@��SX�s�k+U�[���,�3.����X��� ��'A��Q|��n�9��mh|����!���j��Ԩ���ڞv~d�kg����L��k a����_�m��jx� 8~��f���#��t/����h�[��λ����Xms۸��_��7��HN���9��Vӌt�t�ɤ�"W��@ɺ����.�"�z��K9GC�>X�˳ ��&�����q ��F&�VNH%U n�����ZY��2�Nju%E���2�"��p�@�k;-`��2De1��"�a�'n! �T$ +/�7G�� h��� ̴�v9�>� b�8C�l`������wy ��~$����M�M���6�0�DIZZ$ �D�B�ca"�w�ӥ��ԁ^(4v*����2�)���X�iX�,��ʮsg��K[~�9�C7e� ����L,Ai�� +�!�ԁT�Y�H�B��wW������1�o�dU �#m�0u.=�v�EG��m�n������ux��U���Y%h-�-�#/A�i"C1N��r�8����N��MڶH��0UN+L��&��Qp1��0�w�ް ��F��<�_.no/�����p9�_�F�A���$���Wm@�hRC��$y��|*l�l��dS �D��g"F�� I�f&-�ւP$r&'�%��ފ*y�����i����y�)ݮȜ�Q9w���(���mW2$��ՙ�� +.X�m +�ܿBJ+4�`�p�2�]5tȃ����W U�p%�A@��%�3���:F�h��rp@x>��g��J�ILwz:�����q�逰��:\8��D,���S"�j�ƁA�%�eݩ6��A��%�w�krR� '�t����p�˟Fה��G�*�­/-2�ӂ�c�*�T�*�@��������n�n{��9��m��mG��G��^�@�$Z���y?�ƫc����[D�%�0p&�2I`����� �p�e&"��k���fѻ��=���g�u�~�I!��Uo�€0F,k���C�Ƀ�T�s/y�*)�}���k��L�l�ajW�y�^ReI�?5ͽ4��.�<� �Eή�����6,�2��P�+�S����#2�j�9J+OOQ�}�eֱ�/{B�5]�q��T� ��z\zyZ��\F�Jfр�T[+�ɲ4]YڕrF�C �"j:F�*���Z��3 \��a���_�R7�2�`�eTO�l��&� +9�ww�>���07�|C�U&�s~��})s����u�@g�+�͋<6�����D�)�͂C���UU��t%�W�k����\�br,���c�`d<��Wͭ�貐4�4�e= E��F�;XN��x~~A������m\s�_�}쪸<���B�pJ+��q<��j����Ӛ�� ��I�V�u�����'�q�B�(>̗B.���5|�ݸ���0��,�%��jmJ�����.TIγD(�c�ʏw�6C�i������� 8��u~V��9�R�|vE Q�1jT�� əP2�Af{���3�Y�����m������!�㻙p�����>����_|��A7hW�筜���C��Q����-5�шε7Cn����ٖl.�ʿ���>_oJ��eЄ���ظY`� $u��d�~�ܻ�5Wy�鲯!�F,��'50HsTt_�{X1�o$�\����P�tI�&bY�a5d�q�#Iɐγ���[+?ͩhe��Q.��*�����Xe�u.��$��-[0���� �������T�Р�7��/����8�&���ŦF*7�%Ն@*|[�^Gd؋��_�CR�ދ�5����φ`S禿[N�K0("��n8�6�WDq\�� ��佾���]~��&K]���)U����!� ;����5�[����/�������[���� �*e���=�i���|c�ֲ���5�'������ySg7�Qw���o;Д9A����'Em�*>����`~C�P��C� ��ˀf-[�P|��kqГ-����YQ�rRg��e���iii�^w�z�V��!����Ot��� ?��ףF��4�aw��e�^!۶W����:h5 +��=�mC�;�F�ƔD�ؠ���,�۳-��#\(aa9���i[�v���^�f~�;���o&ĺ �8�.�j{�˪�"�[�]��uf��f�6��w=Od����l��-|I|w��;.ofźs����j�y���V�n�8|�W �>�A"}L�4�\��6;)�HKG�ԒTT�ȿ/xD�Υ�]��3�2sĜ~i�f��p����^H-u _�Gvi�3���P�|�ԑE��s����iG9�a̴YEX��w�nL�s��O�7�:' �)��Eml��u덅�!JKT��.�DL?_�f��(�b|.]����|%:cQ ��2� +R�֜HZ*��C��i6V����4YW�&V���͐�뉇��`c�X�^ձGx �Bɟ����Aq�`�ѵ�@��ю�=��Cjd�n�:ct�n#�E��Ap)0��1����oNҴ�Dp‰�e:����.�����O��s�9K��R���i���Z�肂,@jtVz�ˣ�v� �e�5mHQ���`��K̖�c��-��u��sq������t��]/����b~5[��%7�ο�_���H��,�{cC�B��R��!�����k(��̠�.[QJ�D���![K�u:����l*�oj���c���2F1��):%ME�MIڋ2Myk�ߗ��|Ȕ�bδ�=�����RI��'�{�z��u<�}��0��k{L�r8���&_��' ����y��~ ��1�� �qL0H��y�'^Ӡ�^*< %sXr���S�2�O�#7'��439���4�L�Dx�#��$y/���wrs�_����g��a��M�E�d��Q��,}�bg`I�R�x�<�dBc��l�6 + ����Kݴ�55��l2����/���_����8a�o��i&Òom����p��'�-4x%ôU�(�,�N�H=P���" ��������E#���~�5���o}�e��C���)��ip�< R�mڵ�؃�Vg|C�r�/s�0I�DX��>�^���yL�������3ޝ��{���Z�������b�[TI~�G��r�u;���\]��{��HLy(܌�Rx+�� +�D����[_Yӽ��tm���[���OK�B�L��9?�.������������ �+�>Xr8�z�(J�n�L��+ �Q�)�v�3� +M��������� ��h��|��T�n�6��+|� w����κ�֦A�\jV��Q��e7ȿ�J�� ^H��y���oo��/�����cG��aϾE������R��@>��,����:¢@�cK>P�(������h�p'�oLƝ/� �!�xJhQD�ٕwC�;F�i�(e �&��כmu�ž]�7�8j0r�;E��iN�����!��J��&���?+�]���4t�/�m�R��ńc�9m<�0Q9a=5� +���D����c�Ag���ů}0��1z��m{X9􎍷=���c|���.)��@���`bB�t1��e9�����m9S,�U��u�����Ռy���Vj�{��{�����1)���`�Q9�o�:�&8��is��� &kt��Q�g�cYW�>Tۿ6�����_��ժ������j[m�56wX�?&������cG +z�5���Rs⧹��I�Г�=[8�����VI�h��I��8>p̦ + �?n����>�P�PmE\F����P3ͶdI�3zeM�◛J��wY3��=A����|B�Lp��I(�4{z�:ܚ�&��Np�� �}�z���L�3g�-�����"?�'X����>��d-�Dvbqݬ+��7�{�>�����@oؿp�]��ϴ���'ǧW|1C0T�Q��S��m���o1Nuc�'�U���QfBb���7�֚����8�6������AO�5�$�ht����Ey���w�D��T�n�8|�W �M W*��.�h]+l�"�E� +�:���x�$� �� Ғ�٫C�șs�9?���.J��s�UC���PZ� +�&�W�dm���T}K��&t)��Gōp���^R�Ğ��+I�R ǁ%턬 9�� aͽ'Q�q���K��$���lв9�bT�;6h���!�i�ȉ�f�˖+�U�G����je1��Ş DY*Z4PzϦ �x��J�җ.�;U��77�f��rlo��n�e�l�ɱ]#�|��_�ͻH�� �3�6P��T��i���e���H���h��zQ*�#|ґi�����D�Z储���P���?��T��v�M@\ߍJI�;�H'Ix?������Da�D��S 1:��h��=ί ���Q��c�Q��r�����W+M�Rh����.�o��u���;�A�oo�H6�����@��t��t'z�"m�9���# M�Y�\�N�Ř�M��N�>τ��V9��ȱr��K�{����'VC�7w���]�]_4Jb�k�_�H�֙^���L�2@�D�D����;�� �G������_���{���Xf�|�؆+�����\�g�{E� +�ZKl������E�� e%N�� P;�3��|����(��#̱Q5AjvB���"�W��luM{��|\��k��]�Jj��{��+Il����l���>�^�Fw\�t�mf� ���ڠ�f `T�9mP!JC��@F�ow�t��A�_(;�@�\W)�^�k��( +�K���4��*�)�`�ۣQe�{&c+����K�6#;$�:���NR�T�����d���2~���hr�;�� +�F�ڡ���: Ő�ik%X�I�}��tJ�s?<� �p��I�s�E��}�@8֦LF���t��f��/�#��d- ��)C�#D��J��&Ԣ� � +P��(��\x�Mp>�����}�"�h�̐f����l��������WW��>]g�]a�۾M��n�a��r��#�N�o �*2���x�@��Rq槑�w�iN�%�J�\v�$���L؎�L������j� ����6�&��e+�O��Wu@\ޜ��$�s�$N�p>n����W&�0O�q����=C��>zߐ ���n ƅGOƛ�%�X �ܰ���vy���"�*{�/+#'H�����߷�Z���� ������mX�ZX�;W���c�}L�-��0�̱2$Y0�g*u����1ƍ��V�@#�Son.gx&LiqOi�?�(vx���rA�~Ǽ��ϒr�a�hU�Β�m��V��e ����l�餛���,�Lbwq�(|��ƙ ��c���c��S� �Rw<�� ��P�^w�]��3��U]o�6}ׯ808 \�裻��\V�C���S@S���Hʊ���%�Y��C�xϹ��/�����(���p�[! \+DŽ�����ke���)ۚ��w }Z2'�Z N�R�ͬa�"dz�:f��UE`��,��B� +2Њ|%c��w�[\�*�F����}@�l�ZK'vP�3��u#S<�{uG1pߓ赯#X��97sC��ʹf�$]��,kS&���s:_,�św���EI���l���X�H��Z$�|C�B��'T9�h;4�y�NIB���V`�F�Y�4�Y�f|K�_W_r|���͖y�Ȱ��|�����j�au����#K��& �*2���x�@��Rq�OC �[�:ن���Tٲ�P�-�0( �ZX_Z � +HQ ��z�w��������GOՏX�� ��m�)I�Z�KRI�S��5��&�p�D���X?�蘅m׵p�b +BJQ2 �k��?��š�Y�禵>5�7R��W��qs��o6�(�_Q��H��6�s!%�\cn�9�`Pԝ���?�����i�a�+>p�L6�6�F�1��?��x�[&[���`��6��C�>A ��(l�(�oIx6�Z +�M�x��ke�i����0'��@qH�?��KV~ƸU�Jwj��xm;�x��@��7�)^��Ù=�{IUӺ�4��}�.�� ��\ ���gm�=�>�o 3��t�B�ȧ�����C̊մ��@������W3~>ƱO�n q[��|m�������8���>�G���ߝT�n�8|�W �>$F*}L�6>�F� l r��S���Ҷ�#�(�C��@Zj|8�-N�D@����������l>O0�Z�2ړh�|����hg�jL���WO�;/F��;Q���&���Q���2֦�%.���.��hhc�{�me�{cќ2�*�ܲ�. +�~�����D|)�������د8 *K ���胱ml$-Wd��U��h��=̠ٺZ��*�zjƝOe����#�3��a\��.P~��…�#h6��.�DtKGh��;~��' �P��!�"zd��F +|��}� ����@~R +��﮳l��bé�U6Q����jS�^�N_M�ݰs��g/�K쏠�kDѾa44�P��1X񢫫�v� �ez>��Eq� +05�- +�� �-�����|�a�������b��W��Xn7��.�n +l�Xl>����� +,�f ~�l a,$�(�g~�znur+9�BC��bT�m��m+.H�@�D#��h*����$l�t���T�H�i"��qtJ�Q�M�:���i +~]��0�6��}/�;�H'VF;o{�/.cĩ�K����>���a���:���M|K�%��%���Ao�0 ���9�Af=n�Z7M6c������*�'�u�a�}�b�)6 ��X�H>�Q�/ڦ���4�K�%k'����k������h�\R�$k�JXGЍ,I[��8i+ʆP�������J�$-���tE���l�cs�j�sl�!jC�#�l D!|�Zg��R����Q�^���=�Gl�@T������[6�P� ��T^e���Ⱥq�^���lc`��˱{<�u�=w��#�C3f�B�z���N\��p:9}��C�Cg�%:(�R��]���e�u�r����7~bA +x{| �y�@�\�6I���E(8fS'���&�/�b��<>�;��Z��IC6{��U�EP�� � +���N�z�i;��xL/MK����aF��@VLp�Y1�}����[�>��M�u�(���|�_g�l�X-�������3�t �sk�6���T�i���e��m��[YB ]w�&��D&�DKf'������ILe=���qK.[Q>�P�2��U .��$��פ�$����g�7F�&Ѹ�I�j�Z���ғ����D֤���I"��Έ��?>+��HW��Jؗ��{�#����Ta��8��_��&ak�~���i™+ ��[��L䱭[[�Ir�{���C���PJ �X�ͼ�f���Vm�,���ʚ!�r$�T%\����Z+�kNՉj��['��QÛ;��'�`�~����N�%Q12]�� c�;���`�ʶ t*g�أ�A��9#����9"�4� +gc c�w�C�ޠ�u��Ҟq�������E��- +m@y.��TC�B�&$⁆K2��X���Ȳrнbc+������m�d�9�x�Ӹ��Pʤꁌ �������o1wU͆���}@7t�:�����aH�����D@�=�߆ ����R���1��*���$��>��p�M��%&_��f�m޼�ߎ���fka��N�q��m-kFM�W0 z#�T�G��S��IS����@A��*C���i���n�ß��ܬ��W�C�ɰ��z�����.�~���G���>_���؀�Z���3���Oc�-�N�e! )P�*;*�>� �Ѳi���Z��Q�F�`*�?����o\�$n}���Z�qu��$�9]�J��>v��k�3FX&�����^A ynq���P�0擁�WұmIp`�:2.�{?�h�ٛ�=y����M�j�n'���%��v�Z +�5�j>_���� +���9f>������o�A�x����1z������Tao�6��_q0412���tX��6&����]�OM=Io�I���dA��@ZJ]l� �K������;�٬��3̱aE�F��u���/�2�E�> ����{�Z +�I6��y����%iO5�I��#T� �p���u-"W�js�^��`4E�q8wn���A�!ZGt$|TD�~�ۗ�5V _�?����C��c0��qu�qi���1��@G�pu�,�}t�vf��|�6�QJ����g�i�`�h�Qʅ�q3n�;9%��_�*t 4�ή�&�Q�M�Ӥ m������{������(�"�0W5A�vBi�K��@?䔵����r�u��P>{���e���T����v�Y2.\' aέ΅��`���� X�G���Ͷ�֭c�z��4D���@F�/��t:C��ϕ��(G�\W)���= +6y�5�.�lB!h�&��%7OF��w���T+O%���m��Z�x⶧�úo�_�XO�8>�h�?�;< �x�f���kvP�0���MS+�e@��^�> ��x� +�� �p�R@�\s�$]��"�)��br�Ng�l��8>0׺&ka�{� �X?A4M��XׄZt^� T���.�m�!ؕ�iC����"h�7ɐf{�8��l��t�iy�����j�X�� �+L���t�.�sL��9]\�A�Ud@���$�@��R�3OC ~Zz�lCRJ��lEI(��LpGCf����B���(��z�ܼM��y#�O��j�\��C?)I"Z�%�$ �� ޮ�߆0�(���O���g�zS��->�*��e�JX��4B\�5l(��WVI$ka�[�/�GG:ߍ}9�~F��g��!��B@S�[�'��7�.†�!��Vy���oӮk%Q�Z�ݝdm�i�;8 ۫C�0����n��������9��>D��Ta��8��_�ȧM�٥�㺹lB͕�i�~Zylϭ"��oZ��)v�R8�l��u����n|A���d�&��� m<:G?��b���[�Bˈ�}?#�$�䃈T`��0����E��}��Xpjl�����j�-��N_��Z�s���cK%g��U,�A�胂Q�8��[���y@�q�e�Ѵ�Dv? 5�, ��/����S����ǧ���r���v�X��w�>�m �6Xn�|{7�oȂ�[H ��j��´ :��$W,���;Qjs"�ђ=� �:]B�}*��p]r� +�R ���"��4LJ��Λ�t������� a�Y����7��\��b�t���������7ӗ��J�� +n8�{���^�!��'*�/�,�J8����ٓ.�ÿ�K�&?�sxfXY�4���B&s���Oǰq���;�q2�j����v�U�e�?>J�����7�q9?� +K�/�1��ۥ��Pro��{co���q&�N0}3�$�K�����T�n�8|�W ��U�1=������"��>��Z"BsyK*J������E�ř�ٙ�o}����%��4���3�E����e���G�n��)���*�E� �`4�@ "g��+�j>�A aͽkTƝ/��zא�%4 �,cm1�>����P��Űj�L�����f|cˆ���bg�{X��Ƥ��¸�17��B��&i��Ĵ]�$t�/�]�R��f�H<���'�')'��a\���$�Z��y�2�l�zv�:��� �#�@��U���w����[nvժ����ͻjWm75�k,7��}�yw2�#=zI"X`�D�9���CJ��S���hX��^���H�bx�� ���Xs41�*$����[r㕾OT�J�mF�����=�Y \�ż��#Qv�Z��q�I�9��gN";rB�O�Gp�\c�k�V�R��*� �����3ZEݥ���Cgҡ���c���x��c�{P�4io��M̱����X��O����>^_{aM!�_|�]S�B�C����䉤�H�9���[��Z�}S|�Tao�0��_q���U#A|�-�VD�VZ +h�&�yI ���e��#��(BB@�$R�;�{�.//�����<�+���N(�tW�\mMC��)�ӆI�k��u�T,�%���S�����-p&P���5!7�V�ׅ����� �.�a4y�a��u����0�#D�D-igc ' +���6[,Q�&� e8*0(W���b0��a��P�h�@��p +�@�Jp�uK��YU��4��U[/%_M���t�3؛~�r�zl�9>[/�y� ���ٸ:;{Э�C���OvP�0��4m�(�e@��ψ����켇A +Ly� �MN�s�E� ��Ppl�J&���l�\�˧��g�n�Z0}�S����%Ů!4b���(���S�:�h; ��M?�6���/����Y>��4��s|ʶo7���^_��m�̱��b�~�m��:�f�t}����s�r51�c/�0��(G�4��e��v$U�$��^T�����tĭ��Z � 4�U. ���ߴ�����N�/�j��֘& ���II�;S�N��}J��{��!�0O�)�~�MH1�h) �cu��Ǭ{W�!������$�l����s�;��1�q-�@��9L‘���ȁ'1��$]�i�����~�t�'�k��#ʒd��O7�\�wF�$��~�(���2|{+���{�NG����Pz�&�..~�:K���c���{`y896���p�"P?DQt�*��T]o�8|ׯ��T�1-��\'\a�ۢOE�%^(R�+i��^��A�� �H�����y׷}��� �X I�Z9&�P \K�o|��Ւ��Z��)g? -Y8Y�p�Wi�����T��ȑ����R��� a���#gy�>�W5hE� :m��Qy� ��1D1| +�D�~����BF|-�G5�Z�VX �\c� X]��I�צ������:线5�i����V�)� R����=Oa�ƭ����c1�D�ɯҗ8sm��������-�v��A�� +\w�L��=�H�/#��B�����307u +h��/�l��ńSm�l��}(��M�z�*}9a>*I���^�Q݂���U� �: #�P�"��d��6=mJQ�h{4�K� �eQ.����������*��U������bWl7%�k�/�O�y� ג��&��"T��?M9��}�=q���Ƴ����8%=�N��Z �jH� Me�0&��g�:P���ZF��atJ�1�tC*���4�߳_�0��O�wo��U�o�6�������p��ӥ��ؘ��"�E?4u��P�FRV����@J�dX� 0 P��ݻ�G���*�(# 1���rL(�r��@��D+�%-+'����TF��> -�?�>r +�bO�'e)�Ӂd\1^R�q 3���U����+�*#�ȣ�A�M[���i�2�冨$�l �D�~�\�'Sl� �L�G� +�BX4�<`� X� ��I�Ѧ �x�����+����Qdl!�Xy)�/ƶ�}Z���u'�Du׌>��^��� .]@�����]@�l�jKGvP�0��e%S<�;u�1�#�k?E� zs��I�s�u�4M�Pp�M������t�N_�����OJ��0�W- eX���J +�֒ Y�'@(4F8��G�~ N�tlZ_��gZ�� �)�����y:—��������Nj�|�by��rq7_͗��Ƌ���|q7 W�=VƋ��w���}�k�����V��FpH���\o��TdJa�h-�� E)\X*�/�y������3�Jk��nS���N礒$��.�����F&Q��1���aj٪g��a%92h��6x������O�����j����<�J�^\"�c�{�D\2k���zt����CD�@h���b�,5'b��O�.F��߆~�Ȁ���B�݁�Kg����S,L��ۏ�[�9O))�Ŗɚ�� ϟc5�2�@y�2�j���"�Β�_�k)86�⡎o߸V֙����a�c����o�j)qr����EI���� ']y��<���R�|���k����p� �҉ .����欰��� +�o0p�X�j��Γ�_��$�ڵ��(��7l�.��=!��!宯�Fs�j��>��>��U]o�F|篘 +b +�ѩ��� + $�T�)8W���;�>D���{qGҖl�IK@tܙ���9�����$��q%$�k�PB�p���3����j��j~˥�B�/BK֟P|����$8)K��ӆ��k�!\i�����4�:�WhE� jm�B��x� d�V����)�E��j��ͱ2� a;h���*a�js��6`E!Bj&!�V�:��Jf� ���Έ�rЭ"c+Ѥ�:Hɯ�blG<�uw��RT�͘� ��7�M���U4�ߎ��Et�������P�n�`�Gt��!G +|�I�& ,J�����aR@�\s�emۦ,�jSf����b6_���o�7泒d- �兡�;������$Hֆ �A� +�N�r�vX��1=6m(Qأ���F��|�ߦ�"���b����_�����z1ϱ��l���X/V��+L������$\Etۘ B��Q*�i�!lK?'�[�!�*=+ �ޑ�.i��†�Z0U@�Z��T6@�i 6 /.�oUﯵ�2".w��d�N���,�.�����&g�`�� +[�9��N=C� �ɑA�,v��TD���~�`~p��!p�o� ����Bݼt�t����E�pɬ�/��֑*^�t�}�#�cf�9�`P�h՛?��C��}��,Nbo������� z�>�����K�ȋ$���';&=]3U�>G$1&>2r�(�(��,~7~#��+����ke��ܝ��� +��}��YL�M*<'5Y���Q�ҵ���{�^jU�_ bm����!�=z��IlqzT�/G5�uT[z�Q� +�#���"�}�;J�.0�l�����hI�7�p���R���h"Dg]�>�'�'��Tao�6��_�` hb�Rя���smLhk�ۢ� +�:K\(�FRQ� �} -�.��� H�w���ݯo��K��<�k� ���(S�7�K.�8ִ��b�A�Jx��O��'�;I�* ��^I2�*x��NȆP������g�b}��Td���-Z��D�*{���Q[���w)PE��v�/W�+�rGU�o��0����-DU�Zh(�g��D�R-l�K�VՍ��kT�� �XOɸ#��3܏RNT�Ÿ�'�.H~����o"h6���_Et+0��;����2��vZ ##zT�#��$\�&BD)���3?u +h��.�l�TĄS�u6I����զX=���0�&�`��^Y�P �N+)JM�b���P�U^��"��d��6}+ڔ�r�=`{4[ȋ~[yq�������>/���]�*���r�y������v���K@��7o/@�7dAw� "�B��Ru�)����O�#��JB S��&�|K6NIG�U.��A� +Z��GS�}�-�I��ꄼ T�|�uD\ݎN�2�{��dY<����{�o&L0ϒi���ph��9v�$��ģ�}�u}�*琢S� ^�i@ +�R�a�z�t���y�O�����K�H-��/� +t��TO1�/��bu�o��%��A��p���?H�ӻ�{� +�'��X�Mn���z,~���{kp˪ϲ���R+�}odd��U�q��ҟ�s��=J�,’�ߡg#(nͦ�-������u8|xf�G����U���<$ɛ��ߝT]k�H}ׯ8�B�J������ڬٮ ��ҧ2]K���j�#J�ߗK���%��H��܏sϹ����.ɦ�S�UC���PZ� +�&�w�dm��]�뿔�JW�E�iu#)���$m���^tBք����f�K 8[��sx]�k +h6h�K0��� �cD�����M��(������ +�D|��G%z�j�ZY�l�p`Q�*� �>�ic!h�� -K�n��j�5[�.���|=c��Ǵ�q�~h�끌>����7�k��:�&����ۈn�-4;xK��A�a( �m�(�eD�=�H��C.�� b+���57N +���.����TĂS6U6��}�,W�|��M�z�|� Y C�xe�Dq �u���h���㠢�Fo�S���Ep:�G�����k�8��"�&���E��g�������Ǘ���b�߬r�.��m?l���6�n���k@���~����ɀn:�`��DOc A-ÜlGR�D#t�EE���L�GG� v`m!t�F��EQ�}�[�I�0 +�g홛��_J�2�W��,��.x���K� �Y2�~�����k%�@Ig!p<�^XX_�ʍ�b���A�4�H�Q���>>l �����,���q�)��k���@7�t���Í�.�HI�M�4$4�']r�7I�b�7>�0�}�/r� +^�"��*��Xp��3�熜7׬��,�����8x-c�o�$k댗����G쑇E������ėw�ջ�uu��g��Px��'����y��$y�.��Ta��F��_�0��G +�x �9�MM� ''!��z5���v������{ٕt�Ж +�l���y����۶j�l>O0džk���+6lJ��@�5�ִo=[��˚�[�i��� ��d�6���!�'�+!llg + �X�Kt� �5�V�X� ;o������w)�����a�Z��u����W�;�V��d�(8�V5؜�4��*������pYy�ސ���8*�fj� ������v#�3��0�D��� \�*�f����UD7��zt�������6m����=�H�/c{ �AE*���0(?)T޷WY��}�bé�2�(f���._?���0MM�A菎� +�ڶf��5�V}P0 + ���gS.�M&8��ihS��~�*j4[���3�[��|���ï��|^��,w��:����������r�7X��o����}E�k%�����OS�-�N�%�'֨�);UJ{KW�%i�i�)Ps�>���߸�5 ׭��B�q���q};:%�T�mI&���i ��f�d��,��}�u'<E�����ƒ��*�y��M�2C���CAHհ�_��C1Kt����/ �Γ)�ϒ� D^�c%�<9(��e +I��w�>�7=�[%�Ap�)�Q �ݏ?�Ux��XW?$}L$�;1��\���l�c������Wm���i1����QB�_]�:;<�QϾG��3�H\PnT&�"O��͆���._�B�C��}���Tao�0��_�T!�U#A|VJ+"P*-�'�:��,���YV��wd7ي��Rɹww��;�z��]����X�� �vBi�+��@?��hk�tN���Q��Ս�p����$iK%� �E'dM��� � k��RxN���.�a4y�a���Ym{g�!#D�D-igc ' +�M�.Wة&�Ke8*1(W���b0|��a��T��h���p+�֙*���+M�gU�f�ĶV] �J������SYg�7�H��8�3|&����9N\@�����e@�bmzK�Aa�PҴ]���=���_�$f륃T`v�anR +���Γd�X��c�U2QL>��U������O�O�!k���WL%�{��k�ۆЈ�+� +P+�tu��v2��LC�ZT���!�F�E�4���"O�3|I���O�,./Y��rl.��d��"�d96k,���!�ޝ����A7{���D�<��ԃw˨��H���h��zQ*sMv�#n���Z]�Q�r�T�Cq�#��脼�ƭ*�i��ztJ��ޙ�t���i �]���0�<����Hٳ�:�kK6 >,���ے�R�S�I���i�!�Ɩ E�7��~8���W���+����D���í�q��ǡ��ma�7ǒI8��4Q4��$]�)nz_t�E oX]�-!��扆I�{�o͇���\��F��Y�]�m�Į�24��4�:�;뜆��Lڝ��:+��;bҒJ�~���mHs��"�p�2佋�7��_�T�n�F|�W �>؂Kyt�ƪ"�D 0�y +N���t{�;�v��{q'�V hK� �������Oomg�b>�0ǚ5�6-BG���/��6��*86�F�i}w�f�XS:�c�x�皌�AR��UuG���k�M�"W�j}��4� �"Z��Ν8��A�9#T눎d�ρ�(��lw�r��o؟q�`��!t�1����8���XZi�� R#�U���k�O��.@C�wls`�T�N<� �'�G*��a��wr>R~���U�h6�ή�$�Q=�H@��%;(MlP��jV�N��s��8&�}T*Q�.à¤Ѕ`o�b�\��sqm1Q,ޗ�զZ��:5a>M��џ=;j���Vs�����LB�`��q`��D����R���M-��*@ T�h��PV3������������ͮ\U��c�ݼ+w�vSa��b�1"+7�n@:r�G�" q�8Qj.�i�!n˨��T�khe�^��VN�M,�#�(��2 49���� �h�xpgU�9� �� qw7�(T�%S�������0ü�&��ݖ�b4t`�,����4��J�������K��Zy��~/��@��=�eg���k��#�C��0:(&��T�S����ʩ���GʋIc_�۠B�r ����'1&rzgpn�oEz�~��ơ7u��ӧZ�����s��zf�@ʑ ��_�b[�ɉ�� �.U��Mja� 3�/�ޤ2_�/Y�����Ta��8��_�� �]�q[�Mӄ �K`���SQ䉭���I�z�e�{�b'Y�;��@�73o�ͼ}�TM��� �X(M�l�PF��"�O9c�XӺ�͆�oa�_�n���%��4���II2� +x��i#dE�y�;a nM!�|q��d���-j���ڶ�-��#Di�j2ޥ@Nݯ֛�l���_(w�Q�N� +�R�[��B� +���2;�uL$-�����foUYypgȺJ5)� T�Ő�;8�zƞ۞��|!����+\�*�F����MD�b����wP�0����J�=�c���;�m�D�ޝ�A��S@�}s�e]ץ"&��-��b�i9���������hr��i���=D�h%�V��Bc���Ag�W���DpަSц�{b�"�h4ͱ�G�0͗�_��?ן7�:����6�y�� f����f�^�X/0]} ȿ�����Y�}c �P��T��i�!���kH����”�( %ߑ�Ґ�� �u��V��QT.@�q c�!o��~�6�:"��z�d�h=�d�,�S��=�/&g�0�S�C _ �C�;��{8eJM� �N8�v[+����^5����`�K�n�[�m�6x�õV���v9.���[�,�Z8��{ t���͏�C�V�cfIxr0ԝ����>�`7�׍��~�U�E�v$������[kpǪ��x6�V+�]kd����d�m����X�{��K�_]=A�BF=��C}�N�)_��Tl[CG�NJIG�|c>&�I��]� �Uao�6��_�`p�Rя���KLX!��"��:K\(R#)+n��>��g��b �⽻{w��?}h�f_^�p�[! \+DŽ�����he��e�V���/BK�,�8������'�IY*�t���+B�׮c�p�[U,����ZU��V��ڠ�f����i��V�������2OnX ���{脫�*a�i�6`E!|h&!�Z�:$⁆Jf +ϙ�fkDY9�N���h" �T��!�w<�u[��T�X�Ř� �)�����U4�o�W]�-�vh-�x� +C(p]7R0��gw������ T���f`n�P9���뺈��#m�x�Jni�x�.z;`>+I��П�0T`�k)8[I�d��`hT�P�pB�S������R�!Ea_hz4�gH�1~�gI6��$�u�9�����<͓E��n���$O�i��-��G���� �*2���x�@��Rq��!���O�!.ւC2U��$�zC& HC�ַւ�R��QY=����_\7�?zW�h�Zˀ���J�c�:]����~�����p��x4L�\A�!F�,l���; SR��I�m ��a���Š�Y맦��0��R�Ǔ�q���[�x�%����ɑ*N����R�s�C̑��^�A�E���V�D�Y_T�:�G�^w���� GsV�'*p�a�%���J����u��ېk��F����]I��ni>@�I�.�`S�;==3==��o������ӧ��S򖧌��<�قTKF�?f���Sv��7���,'�6���XV��T9~|���%#g����#o�M�Њ����M������yAVy!z,���� � +��. +�V,�� !g�!��w�'�ߐ9O�}�Kю%�WKR-yIn�����I¡k����b��@Â-h��g�z[�Ų"�mƊr��B�a(go2����r��7r(֨�d��/�(a�/&�ȠZb��|����+�%Y^�M� t��fl]��Y�Z��f3l-G���� $���"�B����\(B�U�>�Nooo'���b�F8�����ӳ7��g���Y�ʒ��^��\o ]�S>��)#)����e����-xų�Z���E2S���A��+�;>#'g=��㳓��pr��w?���������9#�ޓ��N�;9?ywzF޽%ǧ��>9�nD��� �n]� �p�O�XԤpZ��T�ٌ����4[l肑E~� +� kV�x [�%$�+^!I��4��#߮������<�Sl�퍤��n�|���.�S|��A�Uk�B V�)j�H���=N�4KR$~F��e$_Wz��Xlp¢�'3A ��Z�i�ߖ��:e�aZ�y �rs��U����\S`9���铑��U��Q�$l�geUP�1�03��6�QVH0��򄽂��ě?�L�d�֟���l7���l�ˊ����t���x9��,]�pǯ +��>xݨ��eD��O�$ڭ��;���t���j�V|�3S�X���Q� ���" [�,��0�#!��Y�IXI�K�)�!�8���Ix�yăiOx�fU^l�s�7c�- +�����M���,X��t��I�_�R�ځ0`��[�f�������Ҭa�ch3 }{��U,KX2�5 +;S3���t"��`��E^�)P[�߯�&$@d-`�L�%s��@��r ����'�{�όV�%��E 8���X�5�-s��p ~deILp7���W���������J��F3���@m��n9<<L%�m�'�����e^T�ӱ~������E.}�L>f=3a,-Y�w�Z_�s�1�s��"�G����J�C��� -���:/��=��q8��d��MS��+�g3�&�)F��jW�� -��9���+�wCS��[.��>���ђ��L�bh�^O��`��ˆ���{)�z4� ^^I� f�K�ga�W�������#�M&0�����̪�@@H���v�*"m�����Y~�"0O +�c�qLɷ��{F>ߢ�P�錡����Y�����N5��G���KO���`�ō[�,�T��uQ���d��F ��h��5�.�B=�iꛐ��>�%3�X�2�Ӳ䋌%1������F(`��Vyqi�K�0C�p�m#��.���C���NSHG.�hGf(r{8_4q&ǎ�y�����q�&�1��n'���$3�C��z��ѩ�%��`\�iM���E_�1�jVV�Z�"k8<� '���-hcbu`I����ƥ`43�6�',�5�OJc��w���x�n��� Z���d�z��w"��z�W�UK�Y�I[g��5ҩr��ަb�P���X���g���En���'��i��1S?�~*��˒U��!��C��s�����z..����1f�i��=�G���wA����_=r@z�1�ҋ�R��@���_7q_����rB��i��U����L�e�ra�b���0��3��.k��H�"v�6R��r�߱�-TZ�?�0�g� +��(>�����bs�yS����|�izp��L�6��,�m��;kp�k2.ɔ��Б~��GУ~D�MS�'� �!7�6(��4�>�4�H�f&h8�\e�]�xPR�_�jQW�2��0���-�9$��� :�dz�Ɨ������������⯟/�?~���x�7�f:%��l�I �[= +K��� ��Z��q@zӿ.���io��Lɳ0����������`|@>� {5���MS��;���oX��0-y\~|��%q���MmPǗ��G�GH����ˋ=�\�����l����/T<�����x�h���k��(|x�3 +?�+Q�����A�D����^z����lS@d^��T��atI�O�������ֺU�]C���s'Z�+ ��e�_��n.}��?�_��qv> �}�4|ߥ��yFF�C � ё2V����f�>&w��a'm0�YG��9��ŲW�"�*���TN��I0���J�d^�+�nX�%B�1 +�+�uS2����:pn�(aTFq p�5���POu��]k ,��5��9��w�z^c�*�C�c�b�>�,_�dz�-�07Y�����/��̇�n9 Q�t@��i�"1N�v��~g�hSO@R��������6�&��K[S�[ +���`�5��`�Z�i4��[��@Yޙ�����7��6�^�;���ղO�>�<����vM���\3�[�)��|³�b4t�?��ؤ��I.5<>��SX��~���%�-��qG�3�uu�8�;��ٻf{��/u��k�� �1�/��D���/�l���ޠ��d��fh�g����g�� Ϭe�".L(��1���6i�KI�/x/������fOn�W�E��©&�e�#xaeY�U��s��J���x< d5���訙]��ˊc�Aq:����L��<�%<唫k�ZH�V�X�;�Ub�l�*��0(��fCSv��i�UQ]V�x2�c.Lj���0V���� +�F�� ��6଄��8�h����,���)� Iˡ �|Od���Q�x�q+�q0`.c��ٔ2VA� ��4^28�*���eeb|!�4���Ry��ll\^���/���C:J�ѭ��ȴ]��L�(%=�0=�v�gK��Hi x!~�, +�U���� �� ⊔�W�h��8���pZ �s�Ƶ E�V��ք���R�b�'M�h[, ��6�%f�2�%X���^FT�I�Ӱ�Dภpa����%'7�-$c^ �<�v���1�=j�4�V�(���Wgo�����E�h_����&�� h���:��{8�t�,�-k+�O��ꑟN�iN2�v��E0��&�����F������l6� ��A�m�d����Uj��3V���9z+�p��\ �M��Gը� _�j�Bv���O�hչ%s 9R�<��!#NLB����P�z�Dfc�o'��O��9�N�q�"6����yU�9 +>t�P� +��Y̡�/b��%��6 |{ �A�����F�آ8CaD�QZ0��l0��[�6Rw!� J'�jbw�.�,��0p��?�l+��r%v����v��:��a�����qSV"=�N�����������oY瘱���C���K-9Z���'Ξ[����qG��P�^NX��g6�Z�q|��6�kȥ�&t�ѯ�4�+R(�(�V-�����*n���h1�����.f�6+y`��Nr.�&1iD�>-��^c�8!��h]:4�Lj���K��e��h�rjI_�7Q��H�����+�Ԍ��� �8���#�SW�ҁ�n�iG"}�E�F�'��?y���d��L�[]��"B7��?$�kg�œ*�1�Cٺ������J�ui%�^�iG�\�V��t]����¥jY�`�.؜� -� +�)��M�[w$ ₷��q��`�(<���3���\��Xl�|X2*��s�iހ����&���nb��u�! ��8��=N�ypL���w�!re-B��$?�� >.�n�2%X<�?M���m����K�Zw�9TuR�$�u���ٽ,��i ���Y��<����SB�ȋJ����o� � 3*|�[ M�P 4p���vy�q�m_�Q@g����ˡ�Rm���iƯ7(���>� OK�\V�W3�.è��>Vq7b�R�W֗>Ԫ��p1�7�J^2�+0r���:_��ꃢs���3~���:�Ǔ���>���갆�#��f~ZOc�n>�R�����"`ķ��"��R���"r>���Ϫ��΢�c� 2�,M�,'��-ö�!��7�"^�)�xǫ�b�B.�&�C�Ёpb^��X{� K��u��'��>[�L�*Qv�Bh\^Ҥ�'*� ����RL'�1�L�qFC4"�9��&���x�I�fy���`�<�X�8ʥ��� ')�T 0`��m�P�U���� �� +�pa ���6)UiUi2r�P��a���r�ÐH�2��A�}�o�&=ڙ?X +x� ��J�����:�� +�:L3�1a�9�.&���b�A)�I�,#_����/��ȋV@Ug���� ���M �e=|�����q���d ���S�g��%�Ӫ�l0���y�e[��N��P�^)�a)�����1�4�7�*kv��WM��ç(IU�F�� +b�Q�3SVPՃg�t#���Y��^�t ���U��^xn��7���Co�O*� 2!k�Pt ��g-��������7�@��+G*��x�PE�ӆ�4��� � +�md� ��%J}�o0��y �+n�J&��� �Td§�bX�Z�g�`��p�����!��%�NpYM���٭v �^���-�)�U���H��@�q<���# +�%�d�Lg�)yW���w�;�vS�Ax�ToU+�B[�1�c��u���:�Î�U|�����(�BhO�{=�+8�Dl;"�@3#s�.�@�Om����3�k�� vG|0���Ns;.��8Ȥ��t��Op��jŊT���# �ׁ �DgU� +�E$��C�����dxr�4��;��61���ٲ�b3�{)R�⸎]V��U��ܽ߱r�V�M�f3��(oR���w˓jI�@o`��A�ie8 2�*����S����[t�K �`�N���&.�;ŵ�d������Y 0�ޑ�u�����ʊiY�c��ӊ�����IY���\n�Y�nV�=A�؊�� >�2iĆ��w��H��WE� �P(vx{�H=��� ���l��`������\5 �}�/(n� ��U�6 Ac��L#��?�]v�O&�ҞI�¬�L�O���ͻ^�0&�&�� �W�y��t�ϑ�刓�z�p�5-�۟h����3� ��M�c�O��$Α?��)��OWY?��",g�F�OB�����x��26gĺ�‼�w��`�Ϡ��,M�����#r|��l>X3;�7���"�߲* ���j�򆊄f�)5c���3[v�k��E�-�� DyP��*���M�=(H���}77xU�%lpO�6�e&�D �VX��Z�h]oU��<��]��tC���@�z^��n>���S��`��ؑH�y��H��*D�[fd�7�Hm;9 oS��������� �5Ys1��i��k���`M76 �*B� _E��ݙU�#�ܩ.�����k"��d��y��6Tg� B}u ,CR2���%SMN��-�k-� dn��]�i(C"��_�/����RQԋ VY��~�3Nu�y�4j��E��q֯�Lʊ�.����'-���9���t�2���QN��V��ж8Y�/S�'�2��^��� e��,�� [�p]�Bp/����wq�~��`r�%c<�� +@"��x�L���ܬ���^� ��=O���S��)���1�h+��&ޝ�1'' �aM�܏�udU�52+��~��m�DZH!�ܶ��u���T`��r,Sb��v��F�C��+RJ�cm� +4��qh@0E�6E�o�,3޹f®�$����V�Y_VKiJSE-�X&��Ž�G��j�«3�:�:*����p�\��_g`�f��D|�*���2c�wE�Xa㦶�V��U� �L��F��N#�P���־0��m�����gի�r�'o�b삹� k�_�O! Y�5�Ŏ�^C!����?X�e����� +����N�r��H�"��b��^]}�͊�~M�_ޫP�����wa��-�0ɖ���6K�BcL�R��_��#��^��Z s�ep�+��۶�?�Y%�n1�$�����+҉N���+�"T�g�Zt�4�ȡ��>>��$�H#�*t�����Ġe85��ɾ�N���������>�=���&Byyܫ����^ް������R�_ߨ����O���Į�$�g8< �k���G��� [����� ��j9!�ǵ��&���� +]F�u�j3/���4��m..���� +���J���ON�;�˳j�N�Ѵ�mTM܂UN���0�Be�ڵI[����U�-���Jfu9�fn�����3�W_ $����y��H'~��; q�aSh��E��Ck=�=L�,e���N�������t��S�����4=����l�v��:@z�_��(F>�&�Ӷ���%�������M�8й/N?�z�[��t���R�I)g���h+e�Z��f�V-,���X��_[-��ߠ4�S �4�c�Xᑰ6վ_�j�Rx mp�%J����u��1՚��:V��q��6f���C{�"o -F��� �,��T�c�eٱ'O��J�}%�[��yP5,Z��P�;c���l��F)��-) &7���LЄ3��,$��h�)��2��r=��,Uz)H �6l��Ax���!�>Fm0�� \p%�hp�����T7����^�3��_zY5By�/����P�@ B=�g�򵸒��6�[y/&��W���Ud����}��e�ށ��H1�Tl������Y��5 $��:\�G�:M%���#Ybz�u��Ǝ�^t�����m���.�ZǴ��p� ��ft���~�^햹n���`��]�J}��It�>����,�#�j��#�9��H�F��R���]d�|Y>U�R3w�3�~�E�$p��� �c\Nm�~Q)W��w��S=�p�q�>�=���"��D:�m' 8�DZ�`����{�v��O�}7�W��͠�[����" �χ�|� G��=��e�/E �]W�IzGĺ���:$-{�V��ŢA���ک_d�uv�y5�9�6���7��?3�&y�Xg]���x4H�+��G�_�R����7 ��1�/$����ܢa�w[�]�5D6qc!�6;�?����>����u��n���eS�6)]�Z�J�C{l̰���d��=a=���_�ꫯ�j����_��tlEH���BËu��%�L�Z�אYW�3N����i��J��r�#�Z�����Ǹ/͎�7��A~�$U���ql�������r4J4���P�J&�74剬qAy���7�f+������B�H��_����]�����v{~x��K“���t�'S5�]M��nL�ޔ���T�uV�zS�D�ڃ���γ�$�p�����8� D޻ܥ)��z�T�D�?���&�]�+�VR�*���!yCS��qC0��=�Y.����5� ZR�=ߤF[�|���[�OÚJ��1�^TE$lx�h +�_�.�K��0�� .z���������=��}|^3Q' �k��QY����ų�.��79[�N��uV �$ �<���&��t�N�]�x�G��v�l�_0^�]9R�����J�VrC +��،|�-���-mx&�%���֘� ��*cMFA��#�w~�`�f(��%���0*#�\�a��o�?^��\N�WR��Nm±��ZD߸���K�$�C��y��m����Ϙ%��GK������z�?�Ymo9��_�5�")�qw?��n�irgܞS�����3�GWY��4qҮ���z�؎�,���#�ɇ9��)������ �TI˸�r6G�o鹒F �E�Di!̘�N�7��4��UN~X�4G���]1�p�J�1˕�����J��%������~S�g�U��l�iC�L����tt~s.�~ƍ�� V��`sn`��W�+ ,�8m�p9Wz�B�Lg�d��{�����M΋`J�L.�a�7�� +�U\�y�уO� ��S��ma�{��i/�=He�4XY�K���%�jY�d괃w�=�/���Q€9W@��b�,i�@nmq��V���'J/����o������O�ۨ�h h���3��+ +�S6��(�.Q\�Js��G�&����*h��4��r�N`4�¯��h҃ϣ�߯~������p<]L��ί�F���xW�0!���z���� +MN( �"�Y O� ���'S`��<��d ���E�*�@��Rk�� _r�@eHu˷X%gK���PKS���8� H��Yi��e�~�-�Bx|�¡3I3��S�N,���)~T��$����s4�:�7�MP�&�6)( +��R�"��*mê)gKn-f������#�F�엁u2�s�Ɋ����2��%k3����&�[�4[�E ?�p9 g�hL��b�L�lnQ���L�H��0�i�nfT L����=�!�d������ț5�r����ƜӨdG�(���Qt�����:��{VhU���ѿ#ɖ�o��X%���X�!���Q��V���pd�`&Xr�������J�ECp��}�xg��%N�@�+�7M��R���:����9GW�u�(���WK~�e8g������[����> � ���.8;��R�wAg�4���Ȳx&�*�`�`��r'�{P�=�￶�Uh��1�'����h���� �����(����ѻ��@����2 Lkv����B+�)u���Rx��N��K���σ� K!z�"��Z� +���Nj���z4�[Mi�.)u�ʃ��2.�&ݚpn��Н�]��A˗75X촳������A~�9�������vxN�u�9:��,` qپ��%O��r�7 ��p�����k߶��p�p�G��kn��]��R�zX�1_�T�{ ���55���ˏ��u�9�ؠ-��2`T�'�h��{��0!`��P+��q�rliyʄ����3���-z`�J�J�� ;J��cZ�ν���:6�����.�o + k�kR��F[j ��gMJ-g��0/e�f��B��ej+B�ey�"�Z��$�Z�������Q"M�%g�&�Z��מ$���)>�c���������O�@Y��~ �Mt�\���M���� ~��^��A��q�j=o����ʅ��=���G{�Z�rn޼�:濼��� �_�mTc̮K���h�̺���|�Ѻ|��%^��J|sw[�Vl5�pwK�VL5�p�K����NJ�}�s�&c��Br��#A\iW{[��>1�b�m��2�3��Jな7h�����n#߬�Msh��x� �6`�c�?n�k��:�a�����zy�k��}}��nL�>�+�V`~죾�x +�^=^�Se-��C�7jm�x0��9$^�LJ��Ow�n&�=���h |0�����ҐTc���l���!�1�# t���#>�<�� ����+��}�v5�.h�=�^�{H���Q��p�71 ���� �{B+����ﰏ��Jn�j�xp�p�ƦûÛ�'� '���~24���ϸG�9Yx�t��p�,��Ԓ�I�t5�,��ݣ:7~�� j)�^±�u^��@�y���$��ש.1�ϯ�à큢�����U<1e1&-�����W���;n�٦�vj��;�_�w� �Yms۸��_��惜*Tz�:��vZMS�c���d2�\�8S ���;����E�d7�v�4�X6���> �}��yo��e^�;�!�R� ���K�e�c�KFC(� Cå�0cZ=���y�BcFZ�q��a&cS2��N"bVn0��;�BD�@ +$i�`)�s@�Ea���i�(Dk<�!Z�ӫ���b�Y��k'��ܤ`R����b��E'�,.b���T�0Q���W�'�Y +T:�y0�Pf�3�)�f���,�PQW��T�B�>x �Z�~��tb��lB(4��އ��B��3�Dh���j�����������ˀ���1��hT�e��ÁT�ȇ8z?9���._}��27"C�A� �0�� +X�g�������rW�p~5���'W�\����G���dz1�&Ex�+ +B*��Q�x�>Z�:�C�2&��%��Ce�#G��J���2��ƂJ�h+6�%g9 oIU�Ws)3+qvW!e4b�� +Ò��>��áUIӲPS��'����h���OR?�P�s?�e\�6�ND^����瀸mУ������x�`�[����ĠbF�!��BBf�����>/�JEHθ6�"̫ �/�?��Fm7��U#�3W�`H�}!+����Ioۇ)[���HN����f��M���"�w(@ƱFxϵ!rwK��KK4���Ms��'�F � �*f! �,�%0��M�.b�9y�+0��p%��rn��e<���@$BFT��^�ˎ`�h��<-4FCҪ0&�j:�Rہ@إ�C�\2y}��һ%[ (Ô��Y���L�%,��Ņ�+͓꫑��ւg�Rf0WB���o�*C�Dh%'�b�e�-�&U�������e^ځbǞ[�?W�\�;��5%OT̹N�}��`z��5_���g�y�D��,�E�C� ���ٸ�� ��8(����.� S@�Ƭrl���n��O�4B���?�xD�*�\_nq�7}� �7�{�Nv(�r��%��G�"3mŶ� ��]�����pm�J��w����z��.F��?G�� G�� �Éa���_�K�D{l�����������c�ښ%�}�T~�й[�V�7i�VsҒxh�e���F+_�����%����U��T{�lبs��w3���z��~d7�h̴�lc�^Նy�?v�ڂ�Q��*�)���p��W�kKÅ�s���d/�5O���K02�R��h�⎀b���iT�pmP�(�NrO�O%AB�GĚ=1OU���.<"W�������F:�tz����.�[)g +Y���R�ѣA�uZw���ώ/��9�u��9x*���?���f��.�� [ �:��E� +M�z!?}� ���-Oz`����(��sX� !��⠵7�*^�[x ǰd����N�X}��4)�1ME��l���*�9���w\���3��Ĺ�L۞�F��j[�Cl�kʅ6te%�]M~�njkϨ��F*��4;>������������1�#�jaS�~�&�6��t�Ϯx[z$��ʉ��. <"Ե��a�&�6G#g�Y~)��ȵ�cn�`��o ;��Pw�P�����6����{2���'�!�w��)���Γ7B���z�ksOU�)u���W� �b���@�Yo����܍�M����s&f{`R�ۋ��=:�ϣ��h��뛰P +��V�1s7���/Vri�t�{��X�����R�uy�[W���t���ʒ�qu�xh�X��+!����WLĕ{�2�2�a +\�d�1N�e��7�p�݋��"��MU��9����UW1��ޅGw�tqXʦ���_}�ޛu!�]��%~h�s]���e�E�x*b���n.�������Y��OH.y���Z��D5�p�u'��nF�wWUs7�o5�헶V�+�'g��͠�����ڇ�D�\؛����:�+6���'�.��}���<�޾�� +�[mo7��_1�JJe)�}98�7�[�z��VZ�P���ˊܒ\)j��~���$;�)j��Ι�3���t���=;�gp� +���0����+z+� ��i�o5�1��/4I��J���(!J �P��E�+���YJ��[1�k")\���D3��wv{ч��T��w K!��M3$�X�@��%�Z n)5䯮'�o�a��?f��1��^�^0k!?�LH q̐5I��K#n�tNd�jG"�H6_hkN�Z�t0AUn/�0��l���Ȝ*��1�� +U~9|=�0�:�m����^� p�!S4��SDS �C$�i���n�]�1��St!� +�Yq���:=�����y�B�G^�ѯ�oϯnϏ^��-�yB�I�̘�1L7@�4a�&�F�7�3k�4���V>�N�M�d��@p �C��[����Og�����r���� �~vssv5�<���x{}��rry}u �pv�����ջP�T��JTBH`hO��ˀ�⼤R�� !|��9��XQiNHJ�)t��cHؒiR +��t�g�MJ��Hʝ�����f��d4"�s�5��F�?�{m[�`Jd�D����aA��ᘣQ>�I�XM ^�ƭȑ����fR,���&R?�L�F��"to*يh��7��wר;�m�qM�D�8lI>R`�l��cV�4��(̊$̥*�����L.�/mb��|V]_Zw�������5 �����<��ެ���s�F��0p��ի�*�M�t] �*�mk��9[Q��դM�$˪�nqYl�Y�#�"���Y�{-��ovZ�����щ}9�W5;8�Se�*� f�,�,fKʕ-(DJ��*8�<��z!boc/M�YB$�]c�CC���O(�b.�rh +��:��Ɩ',�2f"I��5L&�qE�ב��I�fʿ�bh��7x��3�����"5"���z�>N���;(-~QZ� + �)��:��v TSy� $�9���c%�����F#�����u��zT4�zN�H��U�:TR�Q&34��2��'���<�(̘T"�$&� �,E�1�zK��Rk�������T�E`S3��-�1#����W�,QQ�J�2�`����ꀪ�l6��rC&S�� +J_,��6STBD8r���L��d z!E6_��n77�>>�S��{�w�����?�@��&������^�!?�5n�d\���L�oneB?�^���9!�]��t�8U��W]d�3Vu�'d}�pU��0��Ì�b�K9$L~�� ��T�|>nL�F�i[j����10����ʦG���!\j hŔV�p�b��K��!��˃]Y�%YL[��T��Z���f5T�����Rk&������Nz���s)���׆� l��1�H���Ԫ]1�x�$�bjLS� �L#x��S��e&W�d�I��6�2 k�$`A��{�cTt,�!A���O�U�g�'�k�f�PfXf�����%v�B�9�p�q��� +�2'�74ZQE��_�䬈��N��¸ ����^�(<��E���z/�Ӭ]p�]n�������!c�hm�k|�`����o�KY��c�j[��y�=�w+X�w{ ��v8��Xg��L���R8����E��"UL��SºpI|RO�k����/���W�Y�j.����s{_���w� �p��?�� UJo ��ݸ��a[��E �0���ٗ��� C�����{uҩ' �f��&r~t�7i5�7s�ODTm z|<��?�.�&��9�pC�q� ��L%%�_o�|;����y�6^��a���iE�z���x���[�^~{Q9��Y�W�純)��. +�s���&��!8�8�ш�Q(sX�j� =[�H�-Ў�d��屄�y�u�����T�%����b):� �HKĴ�.t;�*{�o%�1t�%�ߊ��0�1t�_L ��?���yoӸ��1���#��L�4g�+���0򅭽8��s�+6��J� +��&��X�G��9� 7� +� �Ƕ~��n �{[�,^��n�[(�-�5PB%�Tz�&}u:�z�0ߔ_� #��i��=*���| p��LЄ�qi����� �\�_hp�d� \����h�j�K�D�����T@V�%8��1��v��b2E洹Y�)����6'� ���� �^� �"���m 7���6N�=��M��_}��U�;����}��Y�� ����h��b&:T9��������l}��P�/*f��x�����c�~�=����残Ϻ��Ԝ +�>ad�� � K��L(�v6��SC� 2��*���Q���G}��2�uI��:�aAx��(mҢwwGG��wOur_�׹L��?o�e(!z*��_�T0O������b[2���x�}�j�9��j�:ݔG;Fa���-���j%p��ӑ$�u5��� j��h9�~�I�V4�`XZ��t��Ά�9��1�� H�&�qHh���J���ZJ�R��0A��b�d�0f~��I$%���r?Ԋ��z%Xl��|�C0��f�[ �!�IVh����D:# j�|�v��7ތH^� F2C�̗���:�p��g�KP��Ԏ�?�Cxc��GUI1���:���6�8{+��,�ɔJ���2R`�y���ǚ\���CQ���c ���X���|.{���y�A�Q�2p†����J�4L~�N�%��޶ +Q��U�{[� Ei�������Vc�l۹$ӫ����=w��"�RI*���m��s��CQ�Q�1�}��z��W��߶�S).�3��m3g<�� B8�隻�5�_H��ĕ@�#�]+���P��y��k�xb�,�k��z���D{J�—q��Eh�.���T�+�u.e��v�Ĕ�T:�ۑ;:i�s!�Up]I��H���eBy�d�^M��'G��Z�]�v��峼����)�{%kz+��b�)l7��:�s�[��F#�7�&��z!����IN[di�Z�q�|�oe� +0�w��;w�r�ީ��\�l�2ۀ��E�` �in��Q�����5��Ay`Q9�֣mM��׬����ZK�$˰uz�{r�۞�vOK�d����&$[s,|��H!-�i +�S<���G��� G�iB��,[��N�2g���7�lGI��C� G�cZz�'���X(�N�� ��*ᑙ �-gvWl� � vJ8�y�1kEYJX�,�2E� ���J��'��B��F���bz��Kn��{j�c�s�W�4������!����ܖ{]Y�W� e�Y �a.��"a���XY��z<�`�Y���R����>)��b]�IQ7aX�b�)��T��|i��N,�r�����.,�m��V�$+盀 mT��I��z�U����E �6l�wi?,@`����Kq���c�|�����j����nTɊ'P�j 8�t�=��u�W%�Q+蘕����t�2�Z���3A�de=űd�6L�ݗ����nb:̟pStq۞��%��EyŢ����6���N<6:/��x\����xGq�b����q��2˂�*:�4g� ����g�Z�c"�ÂI�*���}�FkZWPW;�oT�W���?�47L�6�=��J��Wu}��c���o���CQr�̫x��5K.-�G,���<[���0�kG8�5r��<���4��~��ք?�' ������r�oO�+X@��{{��9�Ct��q�����:|��.��5��>�k��@�N=p�j��.>�Q������~�U�8G�E��8� 1 ��CBr�x�z��I� F�ڣ�����(��k��F�Ɯ�h��.��J���t� �4���'����@B��Y�Bh�W/� �$�{��`"r��=��[4�������n}2����To����\�#�]G;D�4h�}h5.�Ե� �^vh�����K� WU_!�3纡0�]R0�r������r`�3nkĩ�#�-�]�8� ��Tx����-_4�-��,��6M�$u^�����z�+ׇ#%4��rQgˊ�R�p'Eg[�J��1�Ts���H�9����} �6n��,���n�6>���������:H�;mb�f�)���i�+䅒�!{D0Ԩ-?:A�ȳ0@��Oȭ���*�+l�=�_s��)�d��>ɢ��1���:x^�)\���&V��,�H��������*�Z����+�(��4�6�ahT fª�;@is魰���R�i��� ���R����wMo��;k���v�FG�qVy�e�Q��m�j?�<}�*q4�p��j�(:�E�mV6�92]�j��iF������͓�����0Qx��X+i�ci#[VC=��C��}�u�X|��%��js���&�c�aӲwek8ȴl �3jt�EJ�i3��&�=[?���s �������ܵU��i�oڷ;��:��F:�� Z�)_��.[i����M�v�b���ԅ� 7���+���7n�Rd����6g�����X}��ݜץKU���Ň�u ���u������)� +���?�^ �৤���?�X� {D�Ұ!� v�_��/-?�F�8������N�yrmҰ�Fi2hQ-h�4��5I�v$uH��Ո[�Hǵs��P�ף>>]���U�<�U� L C�4�4�vI�@��V$����;-��둁 �k_��iF��Ej��V"u({L%Һ�W��޳ +i(zWҹ{}�d�ᶻ��?~���3){Wm މ�l� �jp�����o�v�k�����^x���� +f�X}�V,���%�����5ud�S��ݰ{{�� �k +Uo��� G{ޟwD�1Bg�]x��9��;���t�`u(�KH�`}K�k4<��&˟6F������o/;PW� �N6�U�� ?0ͽ�Ϥ���K �����Oyy�I�|6h��5�;�A`����T\�� +y�����2���uGϒkPFm�[Xw?�˳� ��ڳ�m�i�b��b�^t_ �Gz���:����a���?�D�����LZ��|��.����cA�׌�|;�.��[��t��� +��e���C���e�/�aw��( J��3W�}�2]a� �� ���)g#��p��"e� ={��� ft��n��}ZS���b��"���>m0�� ^� z��&5�4ئ������-g�����1�A�.l��z�,�,ӲJ������-���WB�b5U���-��x*+}~ċ�'��.�T~zR�/���� +�@S��4^��/��� +��(�$q ����y~����.^:(�$y|�zCW����;��,���|�2�ݷ�q���i��1���p?G�{�k_u��e��iD�n꤈�e}��׳谵�vE��.����r��$4,y���F����v�5��[��;*�N%w�3� +��R�f>rg���M�*�f��ǎ?haOh�l��gNd������.ɞr{�����Ϙv81qR5�|K~��^I@h+��:�;+p��o9oӉi���\妌�1��%�(�� Y*��&�1��,� ��o�f��� �������^��W�n�F}�WL ÕY*��NT_P��X��<+rH.B���K�J�/f�w��$ P"qb���̜�C��:������<�{#xR�!�?{7Rh��0�3�E����όT��L�A����C��#��(a^�0���0�p/S�3å��hv߃T��@ +$k�`%�KA�eJ�c�X�W(�����t>���������١n"0װ��R�}N�Y \R�l"d�0d�'ȞL������tē������d�s��5�2͠TPg����&�/�B�D��,;=뽲�+�! �K&�O���3�Y� ]c�!s"��>` +Ƞz �!k� ��7�̀لR�������n2��|1�5�y'b���r�>,���$�[�1�Pm�,���↋�O�:'A�Me����]�����h���>��g}x?��1}7������d>����n����|<��`z����s<��r�|L�� +8U� +���-Y�t��1a�B�P�Q��HP����j`‡������d�–Oɛ�y��U6Ys)ck�f�1e8d��! +�����pz��к$�i�*˩a���F]��ibg� 0�V�h�c��G�q�C|�����:�r�<�Ej���Q���̸��9����nOT���t��X��T!S�B�F��bv�=g*L���lN3 ��W�e�6H����摒��;7�\�>����2tk�&�6� +��#�GyN���=� +WE��5�Q�N�+nh�hEd�� �M�[S�m�M� +t��K)�zZM�ơmz�͉�]p��˫����8V2o �am�h��E��Y��" (yM��;��ÉъvюL�&e��dF��V *Z��ű�К�pu4��hR�T'X��0���y��'�a��� >ρ�,N� ��1A�jk���K� ����C������˘{�³��ٔ�\tב��r�1O=�ĭ z��yt+����pu��� ��Aiwy]���� +�J..�c���k�8m;��Vn���n��ǯ�گ��"bs�Ż�l��.6���-���� +� +=���h޷����(Y�Y w��������z�޴��{�uK�׳�pzڞ�zk�9k�}>CW�6T���t����4�z���.G�vz5��:DS�ҳs�crd:}L.�y`�\]��Qi߀���Y�o% m>ڛ1Vd��;HE)v6�"z{�h�JХs��ibNf��~��i$�|"鶻(�"����ƅ۟YGkL�0��8�ƺ��W~\0o}�/�C�5�6�2�� +��a�R_�Ȭ����E�Y�A�O�"�ו�^B�B�%�P��P���g���G�Aa���d^���ݐڰ~d�6�٨�7諉�� ���Ox���u�xy=�2��\c���k��q�BE<"0t�(L�*0.�P�� ���RdC�t���O������= +�Zz��E~�(OП�V�I�y Ւ�>���paPi�LMHjū8q��{:Ejm��M����� ��k�����/�W]o7|ׯy� ��1i��@�`� �Pw���y�����y�$K�]T�!��������T�`t~>�9nXr��`Ū���=���jIW,�.�ʑY���B�'�IY*�t�7"�s�r�0�ݪB8� +����ZU��V䣵A�M��e봁�!JCT�r6�D~:[L.��b� �}��Up[t��c� DQ��ZH�ZiS">�P)L���u�1\V�Sdl�M,|*�D����Z���mLe/�X�!>��>�w�[��*��_O�>��Zl��Cki�zȩq`�\׍d����ޑ_#�^��A�T�W�� ���@�\�~4�.�p�M9J)�>M.����_�eoS̝�d- �Ӳ�� D�H��R��|C��X�3�X�Cm��۴+Z����� B�N�sL�'�c<�̇�2Y�9�[����v<]L����r6��,&�����_}�_���Į"zh�OB��({zJ�Zb�lC9�8��lEI(��L�DC�f�[k!T�5� *�C�rK.�hD~�Z�q��J�D�tIj4 +ϓ �{�^��A2�$y��&����P�>ϥ�uk](Z�aJ���Q�\�T�%y9����xO�·6N��B��?�-��:2�85��&UPq�a��u84��<[��N����oL���bC�3����r,��r�5Y����l+�S�B���m��v>�7�1@h����ҐpE]JP/��ܗ�?����&WiO��@[���Z״.!7��7!���'��!�ۙ(7(����8��s�:�ߠZ)q��H�����wk+���-;�n�{9��~�:0���f"d���������vp��!����Ov��긱��K�%&�C�N�]�ٓ6���� ��/Ѕ�����I�� �!7�W��|[�Vp��ݞ�w��o�T���k��a�s�i����6��H?[Ú��і�A�6"p��qK��'(oǐ��Eʸ���HK�cn[�C�(�hV�YJ5;�壟^��08�D�e����Uo�? _�-NI���D��Cct#�r����}8ױp}��~;[����auM��.��<�Z|4�s�����-���N��� 넣 ��צd����a�oen���(��5��*�f�jG�1V��(n���O��k�}ܴ�ȟ���1> _�������U�n�6|�W �>$��J�����&6j4��IpO-��m(�%)+���^����E �ٝݝՏMe���<�9f, �V^�bU�W��]k崤R�Br.��`��"�q��匔�^G�Ĉ�"�u�[a 3ݨ\x� +���� ���B+ +hmQk{�oyۄ��QZ���wc`M����z��e���8�Ѳ��+vh�}B�-D�sH-$X�ֱ��T +���6{�e�[E�Ul��&HY��b܁�O�5�����1�Y$_�/p�:��=9{ѵ�Ci��� ;�9#�� +���d����� 9����Do�� ���8 �t����4m�v,b�cm˴���ί����������+I��� [ʱ�C#9[I�� ��� � +�eϪ���xL/M�Kd�*@+�8����� ~�����_��.� �7�z�\�=��V�eD\��MIS�x]�J��{�o��ז0�y���������Caȣ��I����ؾ���*+M�������@,6|�qG6�J�2{j�b�-�F�1��4>�v�a����X.��\�O�I}�|�vX��L�}��v�8]����ƘoἿ����o9W�����w�������VԨ��r|ׅob�2��}���y��Zb^5�%�+��J�P4*�7��:ҝ}Y�@+&z�p��o% n¡��W:����%#��;�lk�~PY8Vnm,oԓ�ɏ1��� +[B��3�sQ�%�ъ�A�!.ܶ���ܒ ��g˅~oh�p�T�Z(6���a�̒�h����S�ǘ��=���k��i��w�rE9',�}�� .��Y�U��92!�0��O>&��oxȏ����"�o��}q���[�W�|�)��Xߏ9~�(E��d��d���.�� r�}Z��ۊ���n5����v C�Iny�����W�U��uY��/_��%�I����R�K�Ovc�3 +��n����_P��X�ڣ]� G=` �� ����ۓZd%�ܬ�FX�;��\xi4�'�4:G F#�6*c� V.R��D�E�P{7�#����bzs +��~.]��9l�/������/�2D�KR-H�2�bC��B؜\�L���(=��F�JY����.���ؚ&���u ���֑�?�^Cߗ|�Y|�l�3߮����8�I��a�Aj�LU+)tƷ�w���Q�YR�@�+`V��@��(�����x��lF��[����ߦ7����W?�^�+��B���i1��D]+���BPbC��4q�����^�bH�]��~�v!KJwp�h��g�9L�����t>�ߧ�_g����ӧ��bz;��'����.���9��`r�������P�-��ڒ�]�'�{hJ6Vb�\��\� ��E# +�¬�ru�h+�(���A�Jz����G����E��DźZ����:�d<�7j/���2��z+���$� �H4A��i`�4N�B!�G;�!��u2T*tAR� 1zL1�~%�K ��X��-�/C��03:R��y���ġE��u��z�r�X�bWs�Z�E��bhlm���;C�*��c�2�I����i�|iMS��`��Ӫ߾-�;`�+x%�Ж +;����&��o(����î ���Vj���.����G��W�<�JN ��WR���k���$(��ѩF�Ė]��`9���$�yv'Y��/�ɏ�����ʣy�&��$�5�W��(}SO�v�y���#<�*:K{@�!t$ ہ݅�3SM��P��"�y����A���hS<{pcp��RH>�š��|���1��a%Mh�۝���(��(r�^+���X���S̹�R�с��$��&��9�#����N8�VC%���0��QW�ۡ�w�7IL����f�����w�K�9s;��b�y�,����9 +nyNJ�w��+��[a���jI~����Ua�̲�V��z.��SGH��G��Z/[����������381U\n���������e���x\�SǢűC�)����ߕ��-y����i�����u됈� +�O�L�_���N���^/�Jl��<�F0]u[�t�S��De��I�/g���5Zm[w�t>tT�a#��0�mt�^v1���v���������ό�3�<��7h��$ؽs�i�vZ��8LN�2�{]��β����o> )�bN�6x*� �K�@��p�+�ؠ%K{u"��RγQG�;� 7�-ZR��i^�8S5 ��Ɵ,lݏ7 Z��2�1< )���A���b�}��|�:^��5;�@L�oIr{M˯���*"5-?a��A� ��&������p{j:���I����8�o�@��p�J�t@��ݏM�b�K +�=�Ā���Z�ʫ�K�),�Y.���{�������P� d�:� +�8 ��~ߑ��S�ݾ�0Šnliv&� �ݞ:� +�k�~�����I�W2��^���4��|~E��>��FO�=%8��n$y�[���_O�0���)�xj+� �t�j�X����Mn�+;�B7��Ov��h�V����w}��9~s�TM�L&&��$�Z9��U W�K~��Ւ>�j/YH]� +Ʌpڀ�#�9�B�+�IY*�t����+B�7��0׭*�c�0�f�1ZU��V�imPk�����G�]E��դ����(�_,W�� ��/��8*б��*��y�F��`��`�Ѧ�x�P)L�5��.+�)2��&V^J6����ñNc��^ʞ��2qK�z���F� +�A����$е�Bi���Ku�SN�+�n$ ��W�|F ��E���"H���o�p��_�r�y�$]��"4kS&���*��-�٫��h`n�$ka�sˆ +��M#9kI��� � +`�ΰcUz�&��˥ -��a�VaF� iv�w�,�q���/oV��^_O�t�ay����2]��E���Ž'?���C�� �1^�w��Q*��4������6��sH��V��R?� i��l�h-�* �fLe=���!%��|�>Z+�e �{�$�h�.I%I�}H����O&�0I�!��a�J8�#��O�o 5�EH=�c�Ka-�ֺp�!���-����<6��Hvoק����vF_��@����\k” �Ϲ�]��۵`�H��1@�zn�#Gޚ�|{�[ǘ��DO&amڵ��V���+� �h|Eߢ��4��Tю�6|�W �tg\� �Mќ{wF�6j9 ��4���I��Χ��bi��m�"�ۀ�3�ٝ�o�����"�+6�lTlٶ����;g�3��@!�����k?(Í�΃m$P�� ��k��D�(����v�xR��r�m�P�jY��1؆<�%A;����><�9œ�ZOt$C�D�~��Uw8�I���G N;ĎN���y��a9Z�=8L��S�|#���G�m�N�|�/��H�Ws3�L<F7LR.TOø��A$�.^�*v �Oo��7 }T#������4�l�ݱ7��N�I���i"q{�!T�w�,����/���_��өP������%�請�u�����Ռyo �O_��`?B��a���`�I6�� �'ϑm{#�0��rM/C�[��g�Ҏ�e����Ӳ��|�v?o���q��.׻��f������U�u�� +��'A�R��o@;�ދq�L�� ?�=�[�=��4X�(��%��| +IO��AV�l�G��TA���6��W��PM��9g��qrJY�!��lY��s +�}g�e� �2��_�F�T=�%���L�G������k�B�q1�1E���+���.z�d�pQ����,�$P> l)^�q�m%� �Ÿ��`b��;{�Ɨ+�e +f�U�C�p�Wci����{~v}�ZEB>����!�O��߁�v�3�ؒ �HM1=�_����ܻ�F瞧's}���aoX�0X�V�Rܦ�:_]���̲�?f�U�n�8}�W �<8�#e���n����."7E�(ZIDh�KRQ�6�� %��m�K�� ���̙����A|r� ,J�!� !��5���W�k��&��4Tp )#ZG8��"ט�4�$-���(�[Q�X &��1T���a55%�J-�#�B�2j]��B�\ �� *���Tȵ�Ei@��.��6�����ޭ�U��V�-C�G�m�o�3�ҁ�v7<>w�Y*���)J�C*V�Q�S�n��|D_Z#bikĥ"�>�X����ȷq\�uD\��PE�S�?L�nf�����c>q�Z��*�0������d��m]��(�ZQCy1�h�E�]� i>D�w��(�$0MB��$�d���?��yrw7�-�7 ���j>��.��Y�[�̾X�_������T6 ��ZF1�ғ��������Ҝ��/*R � �b��VTk��g��'*m���|�\H�>ZSmC-�`q��*%�IeD�ܐ"�ݖo��/��t�LZ�iQ�FS$M-3�Z2�p~$\MS��8ڟ �Rץ �W΅TB�2��0���GO��ѧ_���-�+�"��Μ�h׋�/���=QYh�}�wM�v�\}�a�Д�g�������sw��gEVt���8�+."%-��l��E�J%�7��gB���r% D�3�)��J�1XE��E�\%v�4•*e̜"���>�2F J��Vr��w͗�U��,Ո9JksD2?�-&痐pA�17^cXq��͸���!QXs� �2Q:�@��Ɣ��e�b�y�YP+��d�,\*���[�`��*���+0N�-j�R~�[�:�#���i�R�Tݠ��(P��j&c<�He�j+��%� }t���Z(%H��MŔᐕV�(-K�C� +���e;�C2�(fT��S�N�/�����&D�)�'H=�s����(9��U�ڮ��^�pd��z�����}��sS��%&nd8�s��`�-��s��m��aJ�E���kP`d{"5[���Vt �� 1���ї�n�O��L�"� �n1�Ю �� 37D�n¯�0�+��>��ж5Uڢ�Ѫ� �x�2ϧCo-�ش�V�w>w:��՝c�եC$�j����y�����U0�D����Հi툵�V +;��j���8�HĄXC��_ )�AYGQ���k��ׇm�h@��&�`�K� +�~>��V+��3��*�TYڪ��*h�y�p& X��U��E��~ �����X�By{|�e�ă<�J?:Ym�MsUZ��4�)6 +�Y��yR��r~�q�pv.��Ll�i�.�~�R��RFT���X�����Q�}��� i9�?<�B�h~�a���A�t_ d!ʔr ����Cv6��A��Ϧ��j3a�@FН�g�pX�n���zcW�]x����o,L����[��pV�_[-�IO�x�洧A�*�6S�#з���&�W$�4z��0��z����i�W�^���5�����F�q�Pb�C%�޾��ð� S4����1�rL���O��xO���� ��]4ﶉYqepG��u'r���t���@�����\�h4�� ���c�@�C�)���w�PB#�g[o��;�(�/Fv��u}�' P�6�3x��)�ъ�|m}���>>�����.�Px� H�������}�6�j�- �4��;��{�?4�S������m��U�-{�qӘo?C��|��3����yv���Vmo9�ί��PڏIII�D���S����Bfw����{�� �濟f���\ڻ[)a��̋��~�:��Z��gp+B`�RK�����hg�R��~�xi��@ ��5`�;�v�7 �JD#���g�"ܚT���и�6!�!Z0 m,,��#[9K���r� "��@�]`������R1>�.�a��1�X:Ȍ���� �PRh�@깱 N��#aC�40���(�`2���2iL���m����a���I�R6�.6��:*�e� 3�X=i^0z!V������;�}���!0�DI�F�U1�� 'fF]����o�����?�����ɲ�-8ᶱQ�,��np}3�<�Z�s`��TZ a��$Jb��Ȩ��(&�ԐY饎Z�v% 6۴޴2E� ��=:��`|o�ƃq > &��>L�����W���f ��p=�L��F�p5�L��÷-@�c�����"�I;�����-E�\������Q*"��,��X$h�9�CPr!=��t��rJ����U1Pc#�˂)��H��P{u:�T�����%Q̙�2�:�r��ަ�����< %�a��/X�+ �Z0!�N؃�rQl1|�+���\=l��'�$h� +��P_��'��.Q�t.���-���Ȃ�0�i�g��1_-�bdy��DR���B�dV$ � �-�m7��¤�S6A,���O�{��6�sh�:]�����<{�Ms�䎾t�B�x]4o��������l��1�7T�x��"��p�A]�л��R��$����L�-���z����6v:u�p��֓V���Q<���2�~���A���/�uM���P;�-{���p)(|�CA�|Fö�� +��ݲ҂��*,��99h ��������Q�\��^��b����#�\h�Y����V�5JF�X��cl��ڜ��P��o+�c��4�U��&k]��,+�/�M��,9-��={�'�w��ڃM>�-8�K�e�����a��׸��I������2���U���Z��9:�{<:t���[ :���Bgj�ח���Xmo�6��_q �9�;-Plh�4Y��� +���v�Pg�d�H���xm��p�$K���e������gY�������>\�� PҢ�B.���Op��Q ��j�ɘ9��� +%  3��~)��B��y�f�3�5���e��{���}�eH�$�VR�=���* �G\h���5#����^^M��!����~B!l 6 +��!R0 ScBFJ�n#�i�:�p�-�X�T!I�Xd#�+evQm�x���*X�� �u��!�%m8䇣Cس�s�)Ww��8�� ���� +�6�̂��4K��y���#�?K5���P@EM3@���[�=������H�Ÿ +q�rrv>��<V>odBƀ��s�)��0��ׇ�[̨\���* �Y��6��XJ�C�3_v�J.s��v�p�-���i�����'���8wmQ9ɴ�H�%p[���Q�Ũ}Wi���r�OP�h��� !�@V���Ul��Dif�_��i:h� aN��bh�n��4s�6��jel�d-�0N�R�1G���7-��p�m"�Ρ �%�t���`���L�����TU�'V]T5��G@�Uqo�JH ��B��k�`��z� +P�%�!x�7ž�@7�����!@�� oX[��;I��l�)E��Sf|L�ASQ!Bo�Ͻ��Š�J�-���v��Ek�����A����� �bN�|Kz���k�|N���t�B�4O��X�����ݛ +�%�Pr�Ʋ1Z>[$Q菮V�qR��9�&�m>&Qb���U���b�\�,c��a�8�C�� �I���z����_���ʤ���"A�� aZ��=���p=͟�D� Dn:�3�'�;�=�|��J��d�~CC����^�w�ie)��nYA�X�p�׫�gΠ��v~��,�bа8hZ4%~PY�1�}C?��>�՟�~���~ ��ރ����a�4�jY�͎�k::`��uֵU����$i�^��׆A�B�l ���h�0��F ���y��X���l���B�� ?�������H�P�k��kU�]�ϩ�sw3w?x��D�|8�r=ԁʓ�]��,�� G[�޲X~%�Xa@喏 �rAA͓�ƴ�kZ�Sj�l�f��[� O���N�M?��JS�u�,�'"�(��&��!��61�����Ǻ��6��[��m ~4;�p�<�X�Dzs�9)�͙�6h�d�I= ������#"�a>���չ���#�����4!�X} +��\���IEw��4de� ]3��x��Q�6��5�������l���0����>}�>?�G?,J>���������� �Z�-�� ���{% +��۩�q �R�ߙ���S�t��?����^��+^~�W������E☾= ���m�����k%�+��.����xum��m��Q������zώ{��U�o�H���)j�� +6���4�V��:���Tm챽����]� ��;ڵ7?�+E���f�ͼ��z]u��8�/ ��q�ES�Kr!��%�W2W���Rp#բ6\ +��dZ���w�9�a��Z6=��}1��HJ[��ç�����CWl ! M[���j.�Ȫ.9�C��61B�s�D�l���l� �X���1��(j�6d.�P�<��w���y|��y��c>������(�j V�%Oت$���t�r��↋|l�ڋ`�Mۢ���3���h0�1�x3�g��f����4���Η���k\,�og��bcq����E�1����)H��k+b�)��tGO>���O���gjR�ڍ)J^q�D�-􀛟��%��U?YK)K�8��E�12'aXE����oۿ�й�ӲQNSQ��@lT��n�m��Ciy�~�{Umwâ1uc��K+�΃��=|__<��\��y�_*絒5)�����q� o�:1�c'����F"%�(��8�A"C��}��[h���/���& +:���*�ސH����<6�ZIC���Qϗ��L)���p���3 � �e��8�8�ñ3=y�o�R{Nхs#I`IB��ݝ�>7���&��}��Ҹ�}�֑[���?� ̖٭�M�ٔ��j+ەF��O}deC����b캐���TL��l��L�j#�[Zc�*� +�����+~oхp��~z��x.���1�:ڬJ� kD�*s�Ɍ\c���Y>lګ[n��U�oaO�4a�����={x���鸏61�L��R�~��)I�ܾ³��?��k"�?��>�1�]*c' �j�Z�~�����J��7L)cMii��S�"oo#���'g�I�����IO��<�A��,��W�n�8}�W �<؁+w���i�4�[���mQ,���F�4��T���!EY��{�@����C���"/z����%���q�e6G���F ��Dc���9*[���X0c�8ox��`V9�`q��T���F�T�La0]^�� jP �4l��h�.�� �E`�Fܠ�&X":���jv~)�p�q�@�m6�*�?C�4�$�� �2Uz�!�ƌ�2�U��<�-�J�69/"���� �o8�� +���Sie]c�QJ�Y�6w�~���:�mA* ���u�� \B�6��L�]g���>�FԚ�̥*mf M?����x\UU�\����8�8~3;��//�<���;)�����Xo���1[ �*�k�#�Pin��F�6��6�B�f�\���%̖}x5]Ζ#�0[��x��ӫ��|5�X�� +��׳�l1_�����m6=�6G x[hJBi�TQLZ| +1[�>�c���Y�2�Lݠv�Q��pc�0���n� A;��)yY��3��k��p��75S�cVZ���,��V��o�C���Cv���&���a�-����Aӭ��� �L�! +�Qړ���4ŨM�� T ��?�fM����AB��l��~՗�^����9�,�K�d �6��c�mXJ�������`�%���88�p��Y�.� �gWJv�x&��GXNz�_���j�%����s���������m��) ��k��A�5L&5��wb�@yϩ��K���q��f��L�{Anr����1g���yefs8���{��7��o����{ +�����W�������0�FЧH��2�Vȸ�*����%*�����R�G���E��(�Z��gd��]�-��}���{ ��[h�|�e~�z/�z�U�n�8}�W�d��ǶN� ���^Dn�b�(hj$�I-IE���)ї8-Z�Ϝ3�3�7o벎������+i��B�%���JUQj�m̒�ym���b��<���$ e���&5�%!U�m�&\�Ff�1���'hdFJ�C+���]p-��UU�Vh�Ikb %����bzy�\T� ��(C+l [ +�V�[�J�e�p�Y!s�W>�T0��b���Z��j%iS�:���:$c:��*�Uӗ�Suߌ>�6��� m�A��:8y��+��T��-;�Sm!$�ZՕ`�{t_�&F |�I�� ̗�ﺁY�v?@im�*Iڶ��O8V�HB�ɇ���,�:{����"c���Fhʰ\��u%8[V���n�~P^B��� +Y���i۴��0{J�� &)���&�4��t�����'77��bz�b~�����t1��R̯1�}q�?���#��%i�}�]JC��R�����SK?'S�ਘ,V +uG�oFMz%��k�d�J����2zP[ؒ���[G���B��#.�z�$ k�*HZV$�7�E����H���ĮF{M%Q8�� ��b�9��ա���U�� +��֍��,��;7{���x����=�y�?*�V5i����,pd�ɘ˒�N��E�%�0�je���ޔQ�W�����!�}~����Ke�C�ڮ�����>|���n�3�YS�òr���� ����G����vs�v��`��a��(z{��Y�sڸ��_q��襐t�3�tC�2��tiwgg�����H��¶��w�,c�W����b��O�%���0��^��� �����0.�����w%���8›�p)4xӺY���{(4�`��i�� rbfL!te"|F�Pk�uH�� +�@� +�R��'F*�R���8Eat`�h��o���Lxd�}�S>�a�M&�fR��D*`��I5����TSk1* ���QO�sŃЀ� T:�q`H� ��1:��5�2q��v`4�*M.�j�@̈́��ȭ��-���AH��\:ࣇ�.���8�Lx��y����� �c�4`���"0C����Z�٬ɬ�M��V�b�]��t^�j�d��Y��r�m0�Cħ�ؠ�ĺ�[�%�1��IT�ORF����EJ��#���]���۶+�H +1-ec�Uɒ`T�4�i���$?��yU+!/0�NXn]bw�§ˈ��U1�rI����Q�9L�#�p���#�M�Fq�t���n�4�#)�=��g����'�d*`F"t�F�(�bJ��)D�ӵ��4໓��@�Y�� �ڨX\�Ko@�y�@|4Y�E����^�i�1Ŧ,`�����������f�������;�/�����n��䛏�D��`��a�g�πcDB5��։�,xE�@��^�#UnV,�؁i�A��C�nu�]����]�;\4ʒvs��~|;\"��S��Nع]@|�u�۾{�k��6j�S�AY�{ ^�� �4�4�b�6F3C�3�\1�7� ��<Ʋz�%v�P��Imɡ6��G�=�)���E �� )���p�Ee5W����b3�{p,�x�'Qd+Ќ/9����V*�;��>�%��:=��=t�H�����k�� G��%nve]YΑ�q,��eA� {#��j�ycK��,%g�ZPu2�ΐ����f6���Mm+mU�ƴe��G�·�o��^W>UȂXI��%��.\[�d�V�U-X�]{j� �KtD���������9��eծ�TK��P4pY-�&n4�w=|;�O��s�  ����P��[ͩ>����)e��R]�$��j�* �u�b�V7���+��NG�����I ��h�z��,��� ;gЕ +�̻�1�k;�3��<�f +�&~;$E>Lфҧj̅6L�Lz [�U\�=Ʀ�)'Ʋ'�R��q�-K�Z����� gq�u� ��“�b���}^�L�� ��\��3Y�3��7�EKT����Th%�Ar�Kڂ�rォ8}i���cOC�̖�gO/u׶��t��W�\�U�pڢ��z�>�k�dbhfn�����#��$�<:yY(����2>�� +���(@3��k��%�@-]�ԭ���������� �V�/'�B��?�zą��=���P_�έ�V3�œ��-p�-��0ҸE�D*d^NU�c�S�?��`�:+=�_�,S}my���i����kkʬ��G#��V(� g��VαBv�y�*=�K)���u�z��R9\�w�8�5������j�nv�ֿ=Yk� ���{).t��U�c� ���p���7�]'?\���\�$���Ee�_���0�uI{ن�<�� ���o� |���o��<�D���cj���Dž}��i_��HWƑ�0�1����r3P��\at�I�Gvj�<<�\<R��� ��-�bW˛S��J�o��6��v(�|��i��o�S��ϟ�ߞ]\dWg�'7U��v�ܸ��h@55� S��#�zTݔ'��72&G�z�`�>n?V���~������ ���۷�]� ſ4G� �˱��'٧Х�tO��w��|�J�o؞¹}��[��__!��am��>[/-2���C=����+Gv��`ɺ��:�߾*,�dv�u(����l Aa �D���-���u���g�"˵g�\no��[�IP6 B�.�����T� +����(}O}k@��Q�� �ú�k�m�׆�M9�v�Rb�.�w��p��T~x]��\{s7��_����-�Ԙ��d�P��HY�9�ˢ��rR.p$�\#���_u�������՝*S���~����w߯���W_�Wp!R��� )���-~��Q)���*��̘�Ќ"������g+/8ܨ�]3��Be2aV( ����#�d�5(�q�ҰTڱ�b�Y�!u��5�K.��pN䯮'���a&R�������.�.�����a�4�$Ț� �L�% �5�3��c��h1_XPkɵY��`�K���G8�� +6*�K)��oF?smp���0� ���O{GOh��m@* ��u�b�� $�j�J�1����y �扨)� -Ԭ< ���XX�:�������C�磰�ы���W7������2�ƀ��Ȅ� L7�V�T�l�rH��Gj"� k-���g�`e%[�2@I`���� \�������Mo.'�~=�7g�^�]M.�o��<����rry}u�pv�7��_�W?D��]p ��J�"���ɓ�5�V��̊�b&bH��gl�a�n�&oXq�k��R��L����ڂ�<]��=��~4Q*�Oo���F,�jΥe�ш7�_k۬�H���i���Ap���ϴ &��9 +�<>�c� `�խH8� i�����Q8 +`�B�'>�K g�q���S���p����ٌk.-������o �DR˙Җ�Q�H���N�B$� �.V ?�O�<לYg^h������,�A�ucGO<��n�% +�\O�v�������8��e���{Ac�����'u.iYh��l�BŨ�B�>�,�����,�\��8y�9{0���-��*U:����X��}�:�5��˂�{`�� �O�ҧ��]��,$[��&�cnLY����~L�%��?��3v���'��J�m�5dǴf��qF���{�3&�Ls�yc?��N͓�Xe�W�*sf[WYf;e����������Y�Zs �sGo }Z6��R4!��ꨔ<�N�;���+�?���VԠ�eϭ����q���aɍasޏJ�UlF,�;~�*+("S �>K&3�R ��"{���I��������w;R�sw�y�n�.� +#�)��sXs0�B-�Y�#��+� #�h_�& �Z��u� +�����_d/��i����!��_�m|I����0�[L28R�dg2q��iT�/?�"hN,����ߍBJ���;H���ܷ,��M�����\� &�Uʙ�s�)��4�}#�^��Br>�Lί۝�!�6�V\D�1�/ $ʭ4[���$�O�.�ˀ�r�1Yp�g�;����#�2�Uhs.�O@�0M���6�XO�#�i,���C��(?�ݡ˸�:\*Lq��B�m��C���C�� ��1�ad��tH�.��ǃ��&�|��P8~0�Ʉ�E�\`�BN3�{��1b*Ra7COjD��n-L�^�x>yw�z�����[-8;2�'�*�7���,�M�'��Z+�����W&\�&^�ε*MH��L7~\���i����%��ӥ�����(+�,�� JM�o�NY �CGmX0S�%���H�AfBA��TfpKn*�E4�y�89)�U�2U*��Ku�dÌ��7�Aϝo, ��R"��.B71[�01 �7��47[H۵��1��&��5�� ��£�x�Fp� +� �qx�m`�,��|���o� +21���AT!B����� OS��?�Ș���/�����_��&k��\z���ߔ{tQ&�zz��Ad�ǛD�����7TN�&؍�oUy�r�vs�g]��Ϻ �uY>�2|֥|֥||֥y|�����NX�� ��@VS�5S�������.ӹ��3>���fLHۯ�(kQ"DH���|�e���cU��� ��L��gx���[Y�*���2�<�2���!�+ۂೱ诣ڈ3�"�+|T���e>�ϙ��pW6K���#~�i�Ϙ������= ��`h�G� k��a<�v�tj�(n�y�&�^c��r�����4�V(��<�*�%�c���+ڹ�Z�ė���u�P��_�|˰�=Ɯ�|˰�ʘ|�i�܉�!|����%BBDž��P�V <�ߣ�$�E����]e�T�0ˤS��wTu�|�Sб?� �\������/JC�1��o���◓�r�_ Ue�B�@0|C�/���*�Pv��@�o�^���U� Vi-[�y��^�M�k&-n����+��b�ll���*,�9��5� k�;��6�'[�(P��S� �����g��n�,}�,���%]չ���r�V���r�� ��}�A���������~�1�xQ%�#*���"H��{1Dz��N.�"�M���n����"�vW*xn�9U �:��݅ o3Ț� @�w�\r�:�w����%�s��w�'�� r�DžūY��}�@�X��.A:��~��7U<���ۋr�JJ�ZH��)Mw�m�}%'δ.��p�򘰏~l�!��kK;\^�Ν�t �nz�����YmSZW|�b��յwĜ0e����X������ tDK�m�:��-9����Ix0��9�e���>�1�s�\*ͷn��wsJ~I�J0ka��k�B� �\?'-�B&�>۪� +�_�T&��O�݈�yr�];5�X�NsÆ�eo��7ѩ�𖥮�e��|�>7��R����C�7�ߕ���d�}�dy��S��4�'r��'��<|o�x� K��9vzF=���6�~�~9y����7�r�-K�d\�x�I�e�}����yƟ�o�C�����A�D��#�O-x7�|%~�((�x{-� �>1$���YF�:�mz��%H�b�T�үUS��`A=��Y8���c/�ͥ��'���u��ſ�w��B.�pC_�L�~�)�z�I��~��N���:w �S���{���;[E�5/g�-��Q��/����)��! �Q?ґޤ��nü�Cm�42 ��'�� �`��i���w*^�N^����*�6�S����16��B��iڢ4ư�|�άR��?�_�/��?}��2�l���e��3p(��ȿ�d����Z��VK,�}w!��}����ED�l_t��S��J���QZc�R��h�Y*~ �(B���b��L�� M����[���x����a��6@gs�G#xJ��l�Z�1<���� ���PB�7T3�F����5lG͟��1<�a��gv �����a<��������;��m[ q��u�����\�v ����n����҄�&�m�����Tq&���Ŏ�� "���9�f��Ƹ��2��@8�a�DvFՎO������@���*E�V9y�Pn�]����� ĩ��%�.�4��r8u�ŷ;�5�g�2(��X��mk�<9)�棻D��f,�h�QR�!GX� �1b6�,�6c .z��`�=�n!a�9����q��h�� +)g�t ��1�a�լ"���h�o��#�?��߃�d�9�������aXG!�40pW} �,��I�=ک���}��U��Nscʌu�w%����;hU=dH�/�����`�|.��茅y9`?+�x��7&7~IEL��V Եv�+��17�����ImI�%k�.X�j�g6�ܜ�P����U�����\�4�agE�zC4�D��V�A ; s�nYZ����R `�،3m0X�n�ܰ���;^�4�0m| �;-N���n?e�+*��i��T�;�� <��Z$�G%�!\�t�� +2��b=�ݶT"� _���ڑ�ݒ�Dž�t�A(j;��W���s�]�m�϶Hf���.�#��+���t{�O��e��,]]����m�[Iխ��Y��/���餦���D�m��s�[���i}��m0?�[^6��� �J�e�C$@Y�2�1; ��m�`P+8 ��O���*�{�\U�Ѿ�aq�9��ܗ���=���PO@&�����Jo�U����9��p���,K����U�� +MV�E� ����=Q��ߧK� ��.ۻL��C��X� +�މK6+�]�lV� ���,{��D��z͛iy7Z��|g{nP���cK�p�FN��!_l3<���~�woqƯ��+�Q�ZuUq���H�ګ�5zQ�����,Uš �Է�Q���Ϫ�5L��PCU��2�7 rEt��m8�E�0p���� �oS���e�q{s��R%b&��?�:��E�oxu=�2�Xew+M,�� �70O�m��3���B.V3ٕ�'�JOF�U�� Ȗ��á�Km[�!�[��'�n�&݌��}K� �c5•UU�5�v�zK��jy��}3�ux�����M�K��5�O���a�Ÿ�t��*�����ݣ�b4%�]��gkW��7��t����;?賚���H�>����鯻(�>[ +��l�5A���]�sA �c4��W�տ�ޞ �A3��'vb�/ +qN��4�;+|�� �:�P�Է �ك*�]��xK�LKQ��=r��;�����[�o7���b��>I�,�r8�;v�&�ո�"��! j5�ج�{$ײ��0Cr�W��܇G@by���o�C��7�2�?{���R��J���L`��{�R%F��F��Fc�BC cF{��~�&g`O�HE�D���] �p��d&�T �/&�ȒjP �l�a��[W�if���Q�Ј+L�L��������0�1ϟI��� ��.�.����`�4��L��"�̕^1#4Q�B���t��biA��f)��-�2� �G8,klT�E)I�1��Q����vɓ�����)�^� $�Bf���ajA&�UK�D<�K��1��'��d3, +�yyK������d<^��#� ��^�����^����>z>:s~Jb44�'�g0݀H�XFb#�bMdC���ZZ�,�4�'(��PZ`Q����`�_L�j��]L�&C�������nᗋ�o/�o�^O��-���~uu{us=��K���7������!��KԀ)y.q*I�8+�S�����ɤɹ� �" ���G�A��^IC�5 ��r%-;��� �B�|������t�T�3����2�̪&V,�c~��f��L�\̨L�O��B��(�j,�J�R�GS� Yx��j��"�#'���/"5�s�v�2 g��$7�M3�����/2���L&^�U�>�6��Ah-6}��i����0�bŜ�ѹJ�vG�J���Rh8��Q�k\x��O�P�7�I�g��S+��Á�blW�x��T�z4���� ���W��>L���T����eu�AM�AD��H8�c�^�>ȯ����<�� +�����=j���H��ߙ�*��+�e&FL���wZ$�>&m���\�~���=a�HZ�� �?�m�Y������%0dJj��w�O%u\�D�e�{ȏ�V) ����X&�e�s�XrEr��s�z����,�Иy��,��m7�5�Bϸ=���<h����v7�q�ދ�"���Άu�Gx䒦H˥Edb�`%�t(��ă\e�Bm�"ΐ��QD��.�Z� +# k�u��� +A}��B,U< �C�H4~\��=Y�c�p������~���ZY�� +J�{��'Vi��ˆ�f"v ��1�E�3�qĕ�np ����LJ}�*J�K��^��qL�dbP[�灔T��LqNU#-ņ�� +[�w?;�g�~)��� ћ +����Ρ�����L��JD�k�J<����MPdV��wΨ���o�əs0� ,�VY���A�;چB���l�((j�De1!�]*�T{(n��s��N��P���kW���Jrz:n�{iXm���+�k +JfŸbD��:�LkL���2����Re�~�GЪA��.�y��� �m�]I���VbΜ�q*7��`Z�(#��V+�֠��2u���[��&�N'c�*��7�8�f\ 6׫O�Z�%��W>c��ݍ�1#U���e�,��)b�1)���0ù�b�2 �EDl�Rإ��(�����*'�9�C�`fM����d�8�3�~����KZM}%��b+����I���0b���`�U�.Y���k�M&�=i����ܹ:ր�:� ۧB�U�a��ߋd������!�S�=%� +��??���$0�5�rY�=��5*�G5NZ�R^��M�l� +1��n89)���A�i,#�g �$���F��,���z���&�`+`���1�b"����L�>��Ɔ�p.�:���� ھK��Ih*J�w=�z�����Ww������7�1Z�����B�T3q�ֆ7VA��+%���]+�����m)�W�w���d����ߣ�����ke�����)���:���I������*9�i,%8�������~�1��"��[n�܋X�r|����[�k����D&��$Yѵ?D�]=Q��L�卙�7�~�EF[�Ϡmq4�E��C����Pi�(������|�z�M�f�.("�2^;�����a������O���l��M��a����K a�l�m��W�Q��o�f��1C�WG��R?6�p$��6 Ƚ[3��&�����/֡ܯ��x�jy��� ��9`�U�����Xa؊�m���޶�>�ږI�;P/���#�e�)���D��Q.�qG�]P�b��:7ki�%T�6=?!��I�ݓ,W%��&��x��� UIYO[�>�m�S"�$����*o�j���� �� ��ᩣ�_���x��Ԓp�(�C2���>/���>�~�u�b�m���zj��9h���T&�Щ�Z���%� BOZ=���rֆ�< ��؄�+'�<��j�;B�5҇��������_�����������R +����gp�.������wA��1r7�Sw/����џ ��O'�өo�L�ϢJ!� :�%<-z�С%�ܳ�/���4U�Ч��6�MQR��˖K�B�[��R,IV�m}֒vI�'�.3�_+g��gk�zɭΰ���� }�z����4۹tfa��>�6?����?Us���L�g3:�F 5cc��m,�]]��?z�ߣ�п��>�+9۾;%�������� �G-��ʼn��F� )B�0R���X7�\tbIު��=��D1Q�D���+a0�H�1�r�l(��Ɍ��E*�K|jTa�U{�hM�n'���W2�����8��=v����W��?�芇��Wgߠ_@�n��������R w(O�t>_� 1�| �i�b��|لz:�g��T��T�X�S�f�[�6�;�^�� �A+�5�E���% +KAyrBc���_d2Skjgt0�ђ*����t�����3�x-gv [9]`Bg�\�pɋ�Q�4�:��mW"*�����tCG�����ř���t� ��0�L���H���ݎ� +N�p�ya�e��]���j쬫Τ�7v}|F�R��{:�ɦ8��w<�~'҄�!9{��~�3�k�пt�����P�Ĝ�#[��������rIw�0�6L�xW,��T�����t��{_:j� 2t�C��,E�b�3N��h�_� �/!��j�rt$���\Ć\à�g�J�+�)�QK�EyiH��3��'>��͞�&? ��nG���z� <��H� �S�����㬢RM��� �I2�RRm���p�8��)xW�Jx�b�~TS%Ǥ�H��cJ���S͸`P �@*M��,��Wr���o��=�S;�,\�@qp��߈Y�br�8ع�,_#�L�2�6b+����'�o��\������m��`�*k�F�Gv��_��� +�������ūf]�-1�pe*��^��.�]�bn�=�SX�Eռݜ� +�����~}��b�����4:�}Fh 8����'����������wi���d���;cu�I�P�4�$B��ˣ�`P�iz�V���j������cBD�j�'�\D���9�>{��% %�d`G�Q��[wO2���%,Z����i���&y_���⡍���}�e{��|�2�L�ՍA�����(*]#/E�C��CUU��AB]����4+L���&Q�҇�Ï<���~���F� ��,��v���нJ�HH�z�Bo��^^Dq���T���i�G�X�!I�P\"k�-�u�,���ff�j�~��ƏB��:3NK]��" �.lRlTC� �k�'nǁ&Y��J��>9�T��x_��!��ozC8.Q/�`vl| +��K�MY�*T�n��?��S�/�����g+`7n�����?_B ��П��]5I��m.v���0�+Xw&[5v]�ى��9���@v��E89�*w��,RZcd�M �V�՟��C�:�ݤE��=���~}�����������X�����J��O{ߜ���X[o�6~��85���:��`�eҤI3 jtjbO�b��ұ�F&�$��//�dYvfg$QD��w.�?�˼��u� �y�Ka\�`��W|+��~T2U���Rp#��z�K���(4&`�%��Y�D�ʅY3�p/ �0å������HP�H�R�J*'[�yA�3�X�W(�L-��d6����,}µ����,�,���T��� +X�p�2�b!��*B� +S��5��F�ti@�*���`F�L�2�1b���,�)��3�*M&����YZ��_��/,��m@H�ƒ;�s��. ��<�LĖ�[��1��3�s�0k +�Eu0C���4&E��zȬ�C��(�}�ލ�w�o�o�'��֠�?W��|,�3�y���5E��� X+n�HD��a*�T亶A +`6Fݛ)��]��f:������ɧ�~��p3���0y�����h6���0����D��h�~���sN�%M9y� +���'�c�<����`)B*�P���Q����j`"�������Dڰ-d�u��Gb�Sj&ef)��o�I�3��k[����� �ܰ�o���6L)��Qo����/��i�������]Y��h*��aQ�;���8���A� ���k�ۥW�O}\���� +��Ur�U��{ɓ��l��68�^�`߱zi���Pة�c�[�N�\H��70f+ � �aKw��J��?c���h� IY��Y*����'�1�7���wvb�����ȱ���������� �� E�s�FR��q��\��'f�Ի��]m��z �Rލ��)�S4tp~M/��(�J 5R��3���r]��������x]�����e<���Џ��a���R�$]�W�b�n[������K���h� U����r�� �Ս���^�ίV�Rln�%��*��m7~]]�6vNݝP^jJ��9���ow�1��״�n�5-�� W�B)&��|�- �v:�5K�/CG]^I��HKK�����KgO��sY�a��R�N���j�߻ً�"O�����A������tz�a�����Hw�=�� 0�t�Nw��|7g�����S���%�0+ξԮӂ���=��*9(wWG����o�ޣs`y�G�x�[�����_9 �b{s����}Uϐg��7�>Z����\`�����mQ����j`N�=h�/޳H>h~%�Ծ�C�v�z��x��/�Yoo�6�Oq����˦ɚeɳ��!vW }����6��H*���?�#)ɖ�$E�%�����?��`�����+�!$Z9!�Tsp �7���� �N��N��$���~� *�)8��Hc=s+a�t�R�V�=_��P)� +�ZXj�w5rZ8m �A� ����1"��L�/.a&3�O��t��J�������fڀHSI[� ��i�dA���\���Lt�6r�p�W +�]�|0!U�WQ��m���.�*5��1��K*�8x ]�`�����w��K��+ ���D/�L +�0uЮ�c�g`���1� +�Y}G���p.7�V��`��̇Q��o�����񏃷����Z0�O! �0]���L&b�!dbEdGqH+#�T�>Q�u7UF�"J��@+���1\���������'��|����������r 7�pq3��zr}3�����$��^�~�J�@��RB�dQLk�e�h ~�9&r&Ȅ�b�0�h9����Z B��ɥtT�H�E�|�ErO��&ZgL��!D�p( +�稜���*��n��̒B���pL "�/ +��RK!�`��Sa,9x���\���+4����D�xFw�!k�L�D�yvp + +Wm�����py�=���!�сηx��G�s�I��^,�����yөQ�*h5��ʹA�,� Gl��A�^���#�$:�;>+�L��˂���!��i`rF���ǩ�8S�p&2B��$T�""M�~�� 1�[i�E13!���V� �d���X�LR�+���������I����؛�ۃt���)�}��`cᕐYa0,� �a:`Ñ.��f�M��u��J*i|6����?u�} �e䀇��9�n���k8 +N/��ׅ�a�4���*_�JdX<�C���D<�r�AA��M�2����R�/�)цuq��a@#�]J�j~z�����‚!�ύv� �*N'�{O6j����ߘ8���T��~�d���� +�fh��_�B94샀Nԙ�$�䖒�'h����L*�S�$�r(�8=����b���"6�EJ���=f7M� #�M��Y�M �'c;��}��u�FF�N��{e��ob�o�b��i{���J�z�4� � +�9���{��{!+���{���4��.&�h��:����U$� 8����J��g��p��1�)�A#������0K��ULL%���0 +���Ȋ�Z�۪ȲF踅�+N ? �Q��v�8_r7ȕί�׵gO)Z��ʭ��rF *�\i��x������]I�d�vs]�����m��+j��ODS��z�T��tAZ�B�ay|��)� ��<ڤ`�����h�]�I� � ����P�Z�[�D�Q���iHB�q������"�Kr��m�o�Y�#��t�D�u�/ h��H�[Zt�w�:�Gi�����k�;��s�aF-"�i<���[����]H#[L����O#B�̩4���::�߶9���`/�-��|[pй ����;@�K4slf`�#R��˅�z����&����m�En�[�60���.���r�>֝�[�� �HG{��m64(:*3{y�=>�xN����]X�ͣN_#�T��1�]��м��{��>aroA!qf���Ad�~�i�BgdLA�6�1�\�P�Y�)"确��K����i89���4��KRIa}��޼S��zjh��u��g�ݶ�Q���5�n�hF��h��m�����^��.t���c��+��(�7� :}���8����t~;��g;�V�j�=�⃶�V�j6��D24�kۜds��7l���e�n��Z6Ec����~i�E�}���v��)5E얉���Q��JGG����d�(��nh�F2�}e�P��6�H; C̝��p +o�?R�,���>��"��BZ�����5�7�h�`D��T9nf����t�mJ�;��0�&�𥂧��d�h)���l�4L��W�%����]�,Ϛ%|�y�Y�]�~:;�?�Xko�6��_qW�]����m�5������a����,�4��To��%);v�6]� ���}�sH�����{���{�.�Bȍ�Bj���+�3?7��W��F_7�G �F=`��e��aް�Y-� +afJ� +�pi]�����r�.Ђ�H�������E�<�XZ�j�F3Dv?��O�/���� ��J_�������P �($� +�.�]q"dhq)lAe�^[��<�V�u��Gs*ev��q�q +� �MK٪:6#�wh����k������g�Wl�k��C�p��.�ڃԐ�U���9[��#�_������R����@x��/�����xܶ�Hp�#c��T������tv�������V�X��� X�AԵ��X(%Z� � 5�Vz��Y���1m��R����A�����`2{ߟ�&� ~���z;�_ή�Ϧ��� ����j��d>�����Φ���O����Z���RƂ��b�����%��՘�R栄^6b��4�h�5ڕt4ZB��Jz�#ӽ�K^�"O�"���(�x}�2�ƛ%j/��1/%"|���!�$�9�X�Ը��?��} 6��y"��ZX�B�l��b�VLx'D��> �-��ػ�m6�F;�S���8����%ZΊn��g��]�B58pC�#�DKHݸ$�T�A8'����Y���Ͽ�u�:��K�.WM�UuyL*��,�R�eYS���K�Nj�P��xq +��t���X�fI�����I��ߴl�9�F��\X+���^w< P�y��`��EN҄Ej��e'�x���^��Cm���`����t�ŏ���[a�닟��gm�ǜ��h�{8 ;�@?L�'�����Jh���֢,g��@��6� �W�ݼ�- +O��ms�ֽ2o�7HP-E�S��:8$�P ���:d�A[ɼ��v��N�%/1q"��N- H������Q�mf��D���˒�Z��UwR;Y��.}�p��[�j��D�񄎱���֝8�~�E�������;�=�M���#&� w�!� �(��TR�� i���x�u�tR�i� +�Y�HB���5����:36+ ��/��֊:�]j��|QCN�I7����|kjǗ�F_�?Z�7!:J�sQC-V��{E��� + +�y �t�($�G̾-=�<Yv} F� +% ��EꕤS���lCO������0Ɛ���=�3�E�[,,8��HZ���}L6Z��� ��I��k�=��� .͌[�&ጸg��w���Q[��� *�wmƨة���,�̡lt��on� +�7���|#�TN:�M�8�Y��c�Չ�1���͍C?�=���`��5J|��<�5~�J����8��`Q n�n��+���{�0�L��7� ~-��Az&2�l�S<�S��nV;3 ���X\O� +���7����E�X�򎙹���C���F.���T,���3��t]+}^�޾n�f+=�p�a��%zb)q����o���W��8y��h򠻀��x [�>t�1���? +��~��w@�0uO|�r��<��-m��#$zӽ�u�`Q�_:{��#�KD�tF��{�~�����n�˄�% ��nT���e�r_�[��y����wKϠ������\J�#�';Q��?IGB����ν�g�>�MI��Q��c�%�w��M���ߣ(�Ѣ/��%_:��~!�緂 +��{� �=� +1ޅ�Y��'�!��������?霧��C��˥PӰzz��N{�X�oI��_QgEk���#>�x���Dg�:��f���t�v������S�ƉV��B�t=�~�h�������۷ x 7R!d���Z�� ��]���pX��r7d��A����x�_d��b�<�e)�ˆ�n) � U:N��������idn20'9�PA"�� �Q;�!z������Ry�\���9,����I K2�0%"�%� +��z�%if4X����+#��Zj4v&���]�$cl��:�Uѕ-��a�� �.����n����Y��s�� +49�,n�>eX:�2��J +�y���ZG�(�&4���60s��u���#��2E7y��epu};�~�S���r�Z ����&+e�d&& +A�%�χɇ_jX�.��m���9�d��5� |��.G0��ϗ��� ���ޏ��˻�����z�;��~��� o���7�����SP���Ұd@�yb���dc%Fɖ�ɩ�@ ]T�@(h���D�f.-ւ�9(9��C�2�o)G>�"{dQ1��D�s|\D�t��rT�v��v�VJ��G�%z� 0K���6Rꏜ����G�8%c��P;�$ZF��n]H~�e�>���1��B˘��QI�x�$�zo2Rd�A채wP� ++�y����r�J�2�'�°� ��D$^Τ�9NE�4 2�أX,�`�]�x�Zѣ2']�� 7%6���3�LZ%�^�Zd��W'"{, ����\;O�j�J�3�xd'5c��MYR� @X�`^)'K�ہ�����7QI�,LPѲ��yd�YJm a�F�֚eB*��TH��R��jM#�P2K[n���Z��N�ɩ�(�����>�pI���� +�6!��w,�������o��*Ѹpu�� � =W���aE&C�G>X��,�f�؂�D����e��_������q���ߑ�y��E"� +t������ +���;�j"�0Ά4���q�ʴQB�V�Y�HV���AW ���'���!r +�č� ė����c�ᖅ&�'�U���lۍ�]J���0Y���LXL���v��.5}�[)b�J��/���I�8��pԢo�$�u_��Z������9 !��G���cIz�<7�_S�Z�n\Zcc�@(K|�I�B6�����բ��G�>����s�>=��$��;p�#>ڙZ�WB@�}_�/*1+?���Q\j�Y��PIV|o����a�O�k ��]"�f}c�ڽ m��y*�Є��J{�\e�$�_a��.\?q�gB��Ck�Bq��;P����׃�1{�����ÁVX��+~��� �P�xW�u���}�K�s��J���F�+�q?t�����9�zQІ��]��2��L/�t>7����*�w��#�� ��(x����x)]ã�C�8�U� ����flg�������f˩�,����lN�dbob���\�N����eob�)���5Z�q���=�L����51��h˫ ��Ȟ����X]O#7}ϯ�K�HPȬ���%͂u*�-Z�V+�sg�Ʊ����n����x��dB`�� ���<Ǿ����$kD�� 8�+!�V� %T +n���VVK��]��+mf�Y��Y�i�~�����n��a�7g�J�*fNh�����рVHhm`�M�وq�YX��*g;CDo~p=��.!��ca �0nn",̵�B� �8�I*�� �h0e&�L��F�z��؉�:#JexUc å[�a���R֡m�����u�B�M�1[B�l�\$��d*�Y���;4^����Z L� �L8O*Kе�J�\d�O�T�Hk�w�)Q�r�ST��Q��Bؽm�x�MŬ΍�T�(��#ES�#5R\K���j�Cz��X�D���+������_H��5�C��'��G�u`���{��|5��@N���~�"�|m%�g���yt� BYGB��kv=rSB� ���I��(���\�2�#��6pc�㒱2{t���r��=8��8G�o��X����-$�0cآ 9�R͂�=1˴qL���� �8�V/En0���du��45t:,U���.��Ry�nN���/�W[�(8\w���QF�wh�Ӧ =�+G;a�{�����Ke��S�\W~^�1z�� ++#����n�JT��u�X �g�9���e��l���Bm�m�2�K���T����]Z�WJ�����RpHrUl4߾q��39w�"ߢ���O�*B|9��ֈ�H�K�Ƃ�9Gk� K���P섩�d 6aB� ��ºR�Gl��a�u7�r�lq��Ơr�v���W��/EV̋�H ;>����u ﰦ*O��ӗ"��"�[!eo�T�_7���B��|�R���t�;:j��T�ӳ�{X�//�_^���Z�W��:��Υ�ʘ).^S�).���N��:wo}s����[t�)�c9��� ���)n. �y/�Do�|jA$�I�i�/x4�Y'���Eį(��m��i$X�\�f�&o�� a��n�Q�lL��.��:�K[RM���k��9���*wZį�Z �5����?[+�lλx�bZ0�X�N.@�)�x��qm5��� ��3 ����㽰� ��)����u�#��-ݠ��R����^�m� �����l�� ׿��m�J��j/DMx#��~Y�}�V�>���@����J�-F�rk��� C�5ٿcr�%�N(�D�Yy�sȮp����3c� +;R�V�[тxz�F�oTu��#�- �\��v}�ܿ�Z^�Otm���i.����I����׻��"�C������=ks7���+::U$ٔ�$wWW�)G��Xu^�e����T�$q#�����0̋���&[�/�4�F���h@Ϟ/f�G�Ǐ�cx%R�� �Ȧ`f�/ɹ̴L����qʴ>z����L�1I��,�q���d��+�gcf��`�����٘+�Ƿ���TvF%F�� +R �Tq>��G7�������LDJ���1,���� K��`"��X��,�M��"���S��Ha"+%�3r�q�gbq0DRn^yd��5V2w�T;f���\i$�����of�Ҏ{�spBo�� +2i ׼��s�D��/R����v�s���#�0"�$�8ǍY������GRM������󋫛���W�g)��9��a��X�"!5H��Gb"� �J�M{���* +�d�GP�h�̀��v�n��f^��\���������!|8{���jxyq�������������_���_�����z�.̌+�� +�� +�m�8��8)�O�D$��l��)���犌a��\h���!saH�4�Z���ȏ ��!(oFR��Ə�NO�}�9�a�~�y3�\j]ZH Q���iT����sř!cG�j��B�̔v�X�=I�\�j�A���'�!�$\�k`���%��`��F�Ŝg�l��%��\���� +D6��=���lq"�6P���X�9vJ.��|�OĦZ�.}���L�=�dx/O�����[�{y9� ��������c*��*������Y'2��& AZ(����Z�xb�Ur���Gӣ��S�,��'2�5 ��*t%�d:ރn$t>o�_��`�Q��ƹiXuڌO���M�f?���K��G��O���?�6*m���Й� +�����c�ix���{�����a��B �W��,�Qk�aW��?����?��'p���f�u�`�hޝb�]�C��f�3�J.~׃�{�C���x-���HoE�|t�0�,�!�4�iؽgiΫ�VE��қh��[� ����Q�3����@`��Wn'�(���`���`$.�N1���ؼv#^�@O� �������@qg��H��i�q�jL������� �D:�s����1X������� 8����� �V`W.�����۸�.�n��B�a^dv�blf1���hA-b!�y�wm$�i�DFHQ4C�j �o��\�[/ W�HՃ34�3Z*���(E�y g���2بd�� �lPf�1��u��<;�/U$4��K�Ө>�D?o�û���g��0��NU�x))K(f?�s�P�R�)�Y����؆j�R���:|��g8���h�خ�B��n�ͯ�����|T �!rˣ�� ����C}��TL3+1��|��Ը�I�b��ٛ˟�n_^�:{�f8����k�(�l����ߛ�۷g/o�]��z��)�t�'p!|�p� F��}���Ż`���� ��q �@�j�Q��� �\T�s�O�uv�HS �=giڌˇ˗�׷�.�r��Z�� �A�g1��v9�!���s����?�����W��P�L�cF�4���{�ܺ�Yq6���g>>�f^(ix���n �Y Ug�4#QGM���s��vzm��&���ڙ_ +(O33fl��83�F�m ��[�\���!�O!ha�T�p�2x�H*i6�`Y�Y���� �G���=F;��x���(ah���)6��%���Q�@�5s� +�r͆����+�U����S����C�KW�E�{+G_ 63��K�i�g4� *��^]c�Dv�R1�6�"�"�I�YU��%�Uyb�;9�sl�������ِ(� }xJ��N��#��@U�S[�L-c)� 稾x{��ه=B~�S6b���'Jd�`�QN��Ń�͒�`��}�s@�>u��r�/�7�b���֥!F��!�s4����i��Ѓ���>�8�;���`��ک����0o@�����(H�s3�c�2aM�HHf,��(N����>�Z-�w#њj�bc���v% �� ����si�)F �b�� ��!�,4�Jv^�uO��a.�M?����z_sM�l;e�dkg��P>� �-6c-��a&��Kֲ@N��e���47umnwI_׺O�\M�&v�{�/_מa�б����&W.�Nr�J�/ ?��ƦɖYy��+���a��͊7-��dn�.I�l� b��0�*I�`���;����NN춅ݟ��,��\�6�C*)�K�V��l�1ߧ��O+��| k9�,���+'�]!m�Ʉ6V���ȄZ@-��=_���d&�v!�|v�'ہ^Q��r_������~��^��i_����y���8�(}�����׉�r�,�����~���J���T�)�0�e��Q�\�V��"ם��*7�����Fr�w���BJ,Ƿ���^\�鵐��5[�KR��Oׄ�F�X�M_w���|\N&��h�o�w��S��SP���� KH��[_e����>鋷"[|M�(9L)4�_)����Q��# Շ*�vʔ�X:{@���g�6��[F B��S�&_����9���ql�����b�Z�"M�)��ԬԄ��_p�1��F�[��`����/��i��v!޳@0���z��R9�ӽ���뭦(��>:���ڇWJ�i�dF��^��.�"2�%qT:�E�� 2�5*����dsͦ�Ӝ��T�w��Ϸ �� a���n}jj ���|e�VډWV��62M�Ai�1�0ž)���[�5ݲE>�ʼn8Nf����B�9/�߭u��M�i���3 ���9$�Y��{����6F�m;�q��{�:l}]no� ����._��m5�[��s�_oS�'�0�5�/0g�FVk�u���-�Pj��c��en �U���Q پZ��Ρ_�nw� ��V�}��=5G���z�&�{����odԅ�i���х���(^iqCEC�y��?{�� ���D��x�-���Pq�+>d%ͳ��6lX�����'e;��6�D���&M��E����R����R�>H��\œe+�E�S#�g��:�l�j�¾�p�rXVü;�*j���K%�+���^�^<�Sx +�ax6.����`��&��0���W${��>��=O�B�D1Za��l3vj���Ң*�OM�Q��5�lX8�l ������Z�m���I��R���Q�E�� �"s{���U�\���2ɰᆺ�m�cJ���`�C!����u���eDm+���j�%?���+c� a�I��m&�' +E�C����u �Q���Q����`�p�(�ٸM8�������S ږ��_.�ʅص� +� �R�D�ַ+�Ǝ�-�����ؼ�v�]Ƶ �: +z�c}�hMi�c�I�m�me���'��QL3�x$���˔����0���| +���J���q�3��?���Z���I4޵�ց�gwMYD-3ie�'p����B��Ȏ���)��\�f�[_A�X��V4ַIXujn�>Ígd���)"9�>aK��^smi�7�_���6� &j��UA��sIZ�f妋2� �Ϻ�{���X�<� +�� ��3L�~�P9�RM؆�n�b���Q��+/g徱бk�xӲo������?z��O�6Y���(_儦����'ׂ����U� �X\���MM+��;�Z��*��Mdj�> �F s����`w��.��9�1l�~x� IF���o�����QՆ�Ԫ�_7Q�z��(. �a�@��T��Þ�Խ��j���~���f[)� k[��3����|z�0d�fy>��-�>ꂑ�w��Z��yp��B%߂�U��S/��x) �S�zN�B́��m��:����zUL�.8v��lb�z_l*� +,��h����AE�� 9?����*���Y��v�q�άV��:|1_���A!�1�Tҹ~K�C���o�w���$��h�E€0׻b�菤1r^�Db�)�m���~"3�=��nN{BОF�F�~�uGe���\�漶غ���[fT��ָ�&�q��w�x{{'�#�� �G����o����(��}�; ���a��Ȋ/uckd�v'`�඾��gl��/�-ؓ(�;wB/F��>��κ`�͸�4�`f�b�Ԙ6)��<$ ��ڠ�.B��BA+�a޽"�Yb�ў�Dɹ�T;?]�pp�%�L����(�貫GQ�,�pwik-w�Q�5��Ĥ^q���N��2�t%E*�>�z{"�'��q���x/Yq(�mD� +���m��9f���=>X��t8��1��%�!c�~t#?�ZKŰ�[��)>o� 9vS=p�r�&�����t���;6���q۬t��t���݂[� �P܊���C5� %�M]�d���n�L*׸"�����?�p!�G���ŕ��W(��LZmq��t���"cxmkq��G�v �o�-v,5�w3� �B`3 +]p�Su��=�E�~��Ze�E�%���L˖�۠@��${�w��_j:V�ycR�x ^�i�n���t_�G�Ok��r��5>��F nq�a����@�{� F�t �)���L���� + Ux7��ko]y�=b�M�x#�V��: oP�`�W0���{��J�W�AҾ�L󿭭�㝣ҹ�_4��Ѷ�=� ���!��R,��۫��x�_sI�4��Z�Y\(X�u ?�:UE��~H�kG5�R��uE|�����pG}ꅂ�'Ч�LT'�zW��0�kU�����R�����ɓO^?x7��&��S�i�~:�~�F��(;c�GڨHHOK>�B��|8x�d;�� Z��`�뢫�%����i{<���-I�-����X���l����9�Ku�Z�zUh� �R��ͻ�v7��2t���,�g�r��+_����\/?�ⷫ�v�'����2��`��[;Tn�Q,1��h�S.l��ZD�5LS9b��Ē������x ~�<1���)�1m{: ��xT��aPL\������n�I$�ڐ�K�>|g�ki��#�'���+���¨�d�������9K#;��j�墰��K��l��?����zW�K�@���:f +}���⹡ ��%�����40�+��tkb�]�d��ٴj��Y����g)/b?p�o�"7؎C#��xt{tZ���uʼY�k��O��e�na�ǯ?�U�{9�?��$������{��� ��S<���z����b~��=�I�CS �q���ѪW�s�6��๟�,�ж�^;崊V�=��-9��=]�E�Y�͙JE�hu�/�5�@����Uz�'���ac���;�{0G^$1m �/�Nc�V��+[�b]]C����? ���LX�j��pW�⦽n����Z l�/M4Q����d6:/\� �' �����: %��t��v���9���iج{�,�j%������:kil�DVj��̀�ӎ��A�ZB d�פp����uij�&���u>oٵ�ԇ�>Dv�h]X"{2�I*%&��~���ض7O���K���W�5�Q= +�� qp��Z��v�o��Ξ��x飪�s7��W"��f���~q'�\TN�*��:�6m�~��d9��=:�G�e���o=Q�L����!�m +�#��n��3�����f�]��v˨������U���\�M펴�?���_]���@�����p��N�p����Wt8��.Č��lˣp���"�j�#�&�M{_p��t� ۬�QԅΖ�%��Ϧ��G_=?}��XmoG�ί�ZV�-i>��1q�AuqdH�����n���ؽ��ӄ�^;p/~Kz�e��3;/�33�y��ZGG58��") るL���F�Rh�ል3<�,�(cZ7k`A ��JSȯ���nR ��o�O,z�� ��Bci�.���i�q&"���-�h|�F�*̆r�z �!4����ǭ�l6k2�pS��Bl]�ϻ�a���櫀�$2��Sp�1����<��26� +�BYp3� I��:�`�Le҂�\WH��h�3��p�u��a��G.?��K��3��C���������9�e:�����?x��&Ex�+ +B*��Q�W�| ��:�#>�dL$Ky��J"G5�J���2>�ƒJt#�����E7d*�I��"�n=SZ-V��0,i�� �Ǘ�>Z�D1- e9ժ�_!���B�``l�#�2 +:��o��#׮ � +P]�@����ы��(���� �����i���3�,㉰٤��\��Z��k R��J���� +֝ա���,��f��-���L�F׻�� ��\���V$��Cr + �� �:���Uכۭ�T��\R���[Z5xg��qa`��j�C_Q/ 큰���1���Qhc�� rR�������E���5�Tf����ٞ����F��SW��>�T���λ�Q�j� 1Z%�j�X[fa�[���2��lө HHe���q��\8~v�0�ؼ��>��;������+i0��_Z:�mܭ�g+�~T2�8f�ܖ�z^? �I1:�.�Sn�� �JM�d��Qe������T��b���JB��LI�����&v��^K[!��DS6��p�x/��� �T��m(4�p+y\�]1�x�BD��^_/�R/�k��Ac�yb��"3��s����﻽Χ�8�8BҳO������FS� ���:��X�h�Q�]�?�� ��У�X�~��78��b(@�sYw��̲b�,1Oe��Pb�̪���HcW֮����·��(�b�v+*ۯ�݄ �>�DH��"�dڀ���'P�m�}�K��I���У�Hz|�v˪.��l^BG�75��KNK!���W�z�2�����Y���Qu˘�Jͬ5g۵=���Gy_u���Uc��O����D��O��X�棨���\��g���q�P����i,[�q�݊f����^h��0a����/φ��Y��{�n���7c���dKX��>#���IF��7���k2�I�^�h�n�����K{�$���^�x�t�L���3�aro�r�|��w�q_jw�t���ڦ�����[�&'�;��7��m���hs�s��)��w����Ta�QR�l��������cPx��V�m�Ǐw�{Z�����U�#9�Ɵ�Z�\r��ʢV{{Z��Zmo�H��_������~l���4i�+�"v�XE0�hi.�wf���?p^$K�;׽�.N@�$rH>$����y:��xD�[�(�\�Bq�E�#j�`��hAD�+ �f1�=�p� ?���|��]|ç�������t�prq�f8^���� ��%� ����IQ��)!p�(�+�d o�8�9F|�#ȘHr� $����9���&b����T�H�t Q�z΢kbbI��R���2����a�``_�@����в$�2W֧;!�GF���B2 +���� ��� +H7��ڄP�j`�$p��bd��e#&�Ejk2�\�9*�Q�%�+�L���$7�2-=�]a���I��i������[B��o����^F2�#�i0��� \��W{�ɡ��z^�t_�� `�b��<3�2ϊn���x>=�Ka?Eg\��*� aI��"'[� ���/O�(��������y�dz�dz*�̲y*�@�@) �ƺ��SU��D�a�Xϟ��=�:9=�^��94��dJ�IZ��u��TȢ:�a�nݥ�_]��a�*�g�Nxk��+U ��}���]q鎏,�~�E��l;�^����F�P�:d"��:�����z��.��)؛H�:��lហ�w5���s����dqi��dM����ss�,̴A����->����3����^������:t��UAf�cسPU�ӟ���Kr��-H�9=;��~�Po��m��8Oh(���r5��\�d��Q"U�)��d�u�d���'�=t"IHeג�_���a��ǎ���Ț�� ��s% FtN^�����h��}o��)OY�uc���Sv�w����2�%*&L]����Mח:r 34����kb � �ل +�iK�fw�T�� +0g��Р��"�Q + �e0A*b1�4�"���Z̚�*�� �R��5�Sv]X��i��e9�ڲ��nQx�S`�lT�Q�J�.�mIʪد��O2�4����")�-;:g���Q0?=*����jV��Bǒ~:��ɦ��Da�������S�X��D>�b*ѝ.�t�%�j>}���R%he<��#�c*Ya�Τ����[̅6�+�iЭqk�H�u���с����{<���{�߰��=vk���_<ֳ?��c��$r?ݭ��%�\���K� +�өFx˵����嚼�(�V*paPMY�m,˨���t͂c3Êsӗ����պs=m`�F��E����)�� {���0�2���)�ʤ�h$u> N� �l�a +RPjC�#w`ߐ��3Dm0����>;8��9~�Y���/����~j%�v�'��\_qaVV�����'��j�d���`�p9:��������Z#���ĞǗ@��v������_u�����- DL��-0h 9�^P�-�R{[�{�2;r���ޑ?�M�3j,|��#ј� 78�X�;�����j�c�J黋��h]Y�*a�!DTrzϮg�fwo�ɂ�����j��n7ݷ0�w�F^m�$�v�}&� FkO5d���u3����85?{7�EOR�Y�����Z�o�ڷo7��SS=�lP�o�bF+٣Lڜj:��E鶑m7��lP~���7ȇ�uBk�I�pm ����R�!y���ҩT�%��h�(��jf+�#O�\<\h�"!_Ni��M��b��ϴ �4�����û4ö��[�jPH�f4=��?̈́�]k�C���MZ��G�����K{׸,fnW�K�U��!]ZJ7y@��;<�.<��M��(W +�ɖ�1s�@�{��ȴ5��Z�2��XL�Ts(��;nhf �׸r������" |����ޝ���R�_�G���!��Q��k,����Q����s{t�qن �z*o�;u�ډ�� R��P�3�͟�:H)��D��G1%S������6�� qytlQ�j S�� +za|�͟��\WWy����(\p��C�*l��x%���\������k�-�!����kF�B���m$�)��7�po����b���Z�""/�gK��;��~�P��>M����b+��O�A)#O�TX�c��-A_�5w Ւ|�J�H�+ʫӪ:aS ��V��&� ���~3��z��� �� ����#�}��'3n����OL<�E�_ޔ�EK�Ul��|z6��mG�`ٖ�r����[�kջ�57rm\�M��������}˶�t�k}m���}}�_��+�]�����k�c��Z{�}뢠���Zp v�v �Y^ grӡ�ǧ��#ݛ��0B~�<�J ������WG;��Xo����)��{�by��h�D�8���چ�48�@@펴�W�ɵ����Ő���vZ��.���o���r���,�F�#x���oGG���G S] +.� +� z��76�\ ��M��@U +�U���V{� +��tZ�Mc�}�>�ӣZ"�^�B���R�Ƥmq���[�������R���z��Rz�=��Ĵ�c��gke����p�p�A��(�R+��������@z�2��@,�7eDjR-���ɰ��x���"w`]CϢQM��� +Q�jt���|J�9]KY +��"F�;�!���0 KD[UTW���D��T�l�J/z���B{J�a�.��m5>k� �`f\ ���T������#���Q�~��P��y��Ǵ����UytTmo�W�5��0��Ə��F׺RT��0�U��[�3��VR\[�9nO�>0�h��f,��ǚ���c�)w�_N5;o�$�?��q�6�8�p�է��T����zx��X\����.Á���Fu��ÂܤFeR?�^ &�IS�/n�^�~�z3��Ew�q���t�q�k��Jua��tS�n�������K.�So�"�Ĕ���3Z�fZ����ӓ�)���Bt����U�'�k��G!O ������Bx �eP;�=�Z���t�|�.�����.����tn� fȌ�4�Œ�Qk���'e��5���W��0@����l(Q�� ��8jQ�z����cz%�.�l�-7QR�͡T�7���:��l���NEt ��д��6��FP���χ���h���ѿ�Z_s�8�Oѓ�0d6W�pɒL�Z�9�L6usE)v��'��P[��W�mp�!�\/1H����V;��#Y&�>}���ϓ�����f؂�ϟ��9�|�7�C�� {B�$�N�/���n�W�ڊc0�J�u?��0�R ��*�A*(�S���2"�0�b%��B��0y�`�#:�!�m�IB�bE����i��%Q��s������ET�IC�Bu���$�y!T�#�U*T�2K��^*,Ÿ�!�34��b*��)3fюT�aL� +E��4���RH��!���\׈�� +�2F/ �θ��(`E +Jb�u�q��.)RVq����=��P �a�o�e.x�Ņ,Y�5<��du�$���B�̤$D(�3F0|�YD�z! �"�d���3H��'tx�,Ф,i�:>��0��<&�����~��ֆ�;y��n����|�����s�����pb���'&y���`�9�l���n2r��[�g����������ߴ�zk���;'���L4���!��^��ֵ3r��u�c�q�z`����?Y�F�L���۠U8~d9w�� ��.�_�q��5�j �WVW^�0r�둝�?����~�5�>���=�Q���w���}7Yރ����!}��S{8�֝uc���1Ўu���SϾӂ�C �O��� �� 7�;0��m�ӷ�K��1�Է�0����'�;t�R?_O}G�Oc9�����$p�q n�{���Aߚ�������[��4�6�qE�o������R� gis�����N׃�����0�oF΍=��z��@��o�Lhy���8�{�ܩV�8m���c)��Ƶ� �|u���f��;y��C�����Ef|IH�D���J�9���$UK.L�w�|�V�#(��N ���4]�e_3y�>�*��!X��(�b�_>h�0&R��$q~ ���L�i� �Յ9 뚕��9]\���ǘ�0OYh��f!gR�4T͑�/���o� �6 36~-�k��?���u�2r�U.m�0��BĚM9�����~�Dʚ��4V*�)��8F �l�eO����St��DNU�����?�_��K�}����l�9��^P��0et�����p +�n�]K~q1��P��H�Z��,� ��p��U*Xa ��/[ +[.�h To�vŨ�Q�q��> �h3�cT/�[������\%($�j��2�1�'թ�U����9�q�@�C_!S�9��W�3�6h��I,�'B�dHh��I�-m���ݓw�zLie�V5��,B�?�`���\ C�U�V�ǎ(Sw<�cbL�Loo�c�B�g-�a��Q|>��a��1Ai�Y�V��G�2�Uk���q��*��iO��)��o�1���r�z予�0˖n�p�}c�`�qg.r}4�us.��ˊV:�0$Tg= �Q�K����rQ�,m�۹�~Hˮ +99h��h�-v-����~_>�٢.( T�BA�9J��A�X�s����0�f�r��YvH�D����,�O��� ���}2qr�������B��N૮~��Z������}>�Uz�D}�XWR���F��X���Ь5 �%Yo�M���a��-��'�f�Bǝ!أ�LFIG��`A����IQO�Z5�����l]�����J���n��S���v��֮Y�Nͺ�g��M�D�� �z=h���������pɳ�jO֢��+΅�sq��g�5S���L�"��",""�΂q��"BU+}q�/Z�$-����Pw �f������=�J����� �t�(��K.g�K�������,k�i�g���1�w��d$�+���t=�����︹�9K%.3���1��Z�`�w�&������F�D������{��N��U��30Qɒ=�ԓ�H���TJ��'�#��!��o��{���˒�KX �� H�O �*�"�j�uW_L39�J��$Y!^�x�E��� +������֕�e�(�<5[Э5��G[��P�;�n��m�O�Ώ��l��\���J�;W�O��T�&�8�D��ZγzA�HGbJ�XO,��g;��r� ��oY/�9n�\Z� ���5R�N�����=6:W��r�����hD�K����ԕ�;��@Q9tP�����G����o�i1j6x�Lʸ�S��ӭ� 2������U� +$]�e��Nݤ����O/rff�pسO���"Ѓ��ya�jFu;'oC����I`-����dB�L��H4�z�54 +� �;jN�K.1�g��fC*��΢Q���M�7u;O��$=P����*��3�k���*R��xQ+E�=�#p�<��x'_*��$��]B~���u�c��3����)z��� �I��0�ÿ�����}3�;��B zf� \b��/��"f��śIBY�vQ+]r�9��� �n +5�}X���H؞! Wj���4ڽ�D2�d�Ŋ3?C�*_k$4�F�ѪV�_k6��m<���f_�rw���8�?��fe;=E3��� �č��\�MP�"�(�r&0{��, ��8m�|����r����rw�zp69ח-���_��]>�Ø�Ү�˿��bQ�"��J Y���a��*� ;s+׸�l���o��������(5�p����J�&1 �٠ ::�c�L��ݜ/-�j��=9��E�3r�Aݝ�2k�*=*����$�Y�|��;�� +�Ie8�6�-ީ]o�ہ�p݋� +��/��\e"(Ss}hߥ��I�aA6�7���)[mss���#��@l�lu���8�>Qa.{�"�"�N����n�+���z�ٜ~�����UT?V��^��E6 �9e�|a���Q`�PS�! ��l:]�<#|�����M#�����Ё_d�������C��r�=8�,X�~�/�Y�r�F}�WtT�t��<��I�B-EpЎ*N�F@S�Ġf�l������"z��A���3������]>�O�^�<��0���s V܆ׯ^���ׯ^�l�!�S�ݡ� +~e2��7���ߒ���`�HT(�1鞀�1�JK~Sh.2`Y�B�(Q�͓�1�3!�\�AH�W"�33�&�9��ȥ�� &��L��#�D����B,����2B �o*^��M��դb� , +�A�f<3��F�ӫ�R��<�N���\Aʕ&������*�*N_��`óu��lr)�"ƿ�T�&".�ic��eə� �%,�F�Y�V0�3�k���8FndiM�H����kU/��T5�{��@J@ �,R!�L.�Bh��LZA���c3)�E���&���L�S�A.9E�����@SjM��� �.�O�����>�Cg�k/x�k��p¥7:~�xo�nz~�vnpj�g<{| �o� �|p�&#��'���q�:A��`4���OCcM/��{��B�SRsv�wW�?��ǡ�wGnxmv�p�1�x��`���Cw0�>!M���  �n0��3�;���GgBpi�F;5�_W���\�?r����0t}g�f�Ow�C{ԁ`� \����\MF�m4�|2d��g�C��о�?8X 5�CNL}犈{L�A��Ё�74���;p�sy�1�4p:0�C�C�'�w��9}�O��GX�8t|: ]o܆K����a`Oghl퍍����ׄK�0����K'�t|pǦ��l2G�� \_��z~��,��#��38��#�On�Mh�n@k�r�O�5xSR�8m8�ǵp�ׂ{��K���&$� p���. �.+�י�>g��EJ+��",1�Y��B�t;�Dy��jGHt��@�>�1f�0�C����˳�Scr#�s ��4�urB"�tS��O*O�Q�a�ZsX���8-�Rϴ��'�ZU5�����.1Xg�o�2��^�1KP���P�d`+%b�4�G`R�'S� Xw��^�,<�g�,-�MO���˳5�u���L��kOϖ�s)4�tֿ��;��2�ӹ�J?A�%�t ��KDP"KsFm�lI���?B�n�#H{���Z�Y�Y��6ʜIK��}cn i_h��1(w/ORF�B�7�ݷ�YBAN?g��I�|�J�ENިnJ"��ԇ��L�-���?� !LW��*�<�eo�0�V����ʼn�h�;v� �(�vK���@Z�>2�� � d\�)Ө�9��R�j�U�n�2Z�ަ�� ��} �X��4���F�Y�� +�3�*|�LN�Ld&��4�ks$�+���s̒������FxQ(��8ߗ\]��'�s)c̫{I�Ri�q@)��65��j�gu�LiYĚ.��s��}�r&٢:4�n�%v��-�ƾ�Iy �"+ D�5+� ކ�V�1W?��ϫ����wJHmm.o��|�_ƾ:J�T������XA]�hq�A�� �>Թe�T� ���U�X{���J��-�� �=62p/|�9jJ����S���P��4xAĄ��UA����YF+�l�@�M���� ���~�JXD`�-V�-:��=J��"$8cE��[3�sQ���_v'eU:�LUR�Z���+��h�����]��g�U˾��V� �oϔ��>鍂�Zj?�k�V� ��i�v{��ޙѲc�b�1*%� � )ɮ+ ���j��ܮ��ԣ�k��u� +NF0(]YM?bb:�3���G�z���v�l8���#,[�}��`��a撉rYA��������M��X?pqʘr��?BV�)����N0D�D2|�K�:m�p��i` �O;{e߼q�{��dɾ�y�y�,o �s;K��A��R�;��oQ�0�ү�z��3��0$�p �+B^�&q�.�#��ܓ����H;���߼��� 3�8Ng3Å�S9͵LN)��>EQd��l���G�L�c-V߈,åSA�����{+��V��t��?ȊFvÌ����=��r ��������jn�N�RPdHYB��%3���t2��nn��� x�Pm �r�0� d�х�z�=28 7���ˋ������EV ����"�O�f���UiV"�y�b�Z�?�:�:ku*���Cm��c���r����Q�Ll�=��h��/�uG�$\!�#�h7�rA=���{�Ģ�r\�nH>�)�,�R(i�Nx�ڽ���W@��mӋ�~:�zN�*�� �]���8dw���V �Я��KL� +�YF�\#Esߥ�:F��w̩XE��tg\�n��bQ��ké{!{��ȴ��v�yC�g��F��� [g�j1tM�1!�e���Cy�o̵�$�m�Ŧ��߯����Dު�H�n����τD��z:��)�ޖ��_Ƃ��0қ����s�&�;�+���.�$Q)SsTV�g� �-ڸUn�:m�x�����L�m��]j��7��U׳(�pGNQԵ� ��h��QD�fW%o�h����[e��E���p�����n�;��N����7�������Fv�� 4��ޖZ�C�{Rw�B�Y�wz�c�Z��������yv�:�D���f��b)�U;�/Z˝�l��6p̷��b{&3�E��e3�k�ƛ����ye{ +� ���,�;J~3w���:��u%7M���Uتju˶��V����1K|^=Z��� !�6 }! +3l��ycM��=x}�d����<�s�6�����f�NRG������*Kt�9Y�QR�\���$d�������o��)Ң#�S�db�~�],���2��;���=��"���r����ͫW��y���IN�($��J�����t����{� C0�H������� �Ғ]�5`�(0J��O͛ Ɖ����+Ն�� ��_�5�D��'��0��Q�bZ�")�Y@�K�A/),D��/�<`8N�A+��1]�A��H��E@a�V$Մq�\�klJ$Ņf>m[hz��Li��G̃US~H؊��{�a��(V�0.�fna �BV�.(RZ偐���DR���`ŤT�k�B���� }C$M�%f�"꣝A$Z�D���Д�q2;q�0�>�<�)L��Gw� ��3�N�'�=��� N�Á�M�7@<�y��|6���7w��L��z����<�������� �S��z���L�������}h��|f�9���=ug�f�%�) �c8u��Io4��Cw��`=vg#�x<����7s��a�CH��7O@�?칧�`����|tF3����R�a���E�G ���б�F�a�zN��e�݁3���m�N���8?;��a��l8{(ȩ��3���! z������J��=� #���h:sg��け���>�}g����|�aЛ���>����l��>�O]��rG3��擙;��d����x��ͧ���z<2<�N����0�*���ę�8�#���z(���s��|ϱ��7�1 #����������'w괌iy������gϑ}���Ա�̹mT �1�]$�v6&1�N��|��0��Ob�'3㧈�W��ꭵ �{��K!�t������j5F��v �)d>��Pt4���܃������lI��ʳ�h���1�#���?t�qM�h�2�QPI%��K?y�L���̙��~|�IvM4��ђ�q�����FetPټ�aT�xM%.����4iL[S�vM$_ y�{� ma;��˱����5���t~n�#׾n�0�q-�o^���y��aA��k%է���/��}���r�w�T�%��� ��Y*���\�&����Kʯ[y�G���_��GBh�%��������ٶ�����wս��RM��M$���׍_[�O���.ڛ���M"�� �K���4hm�V��5 �a�͝�� +�����h-���BϹ"���_�����v������63����vg��}� �`����ﵤF��X�e��3Y�����f �d �廸���է"���n(�,�G��K�{Q��P��y�s�h�_�'�_B�?t~ͤ���;_|jT /i���]�cL�����64�B��6\�5܊����h��-%�:���Eh�O��-#r�_4�#{q��.L�5m�V�����/��)UvZ�>:�/j���( +$� C���ĦH��BE. ��U� �m�o�uF����+������Z������Tnï�/��n�I�0�/�1��{���:ڄ������ԣ�Cb�u,�<�> ��&D*�H)��V�`$��j�ū���%� I�Uy��ҷ]�u��!$GGc�闈��U�H?f��E���.4�h�$�4Rۀ�( p��ܯ��r�7�|����w�B����$+�3���,YHi�*'��k�t��C�V���1�m��O�d���8W���W<+Xgv���AN��lWϼ�v%nq�#pz�&�y7=yi2]�8v��n����NP��AQ�9 ��+ +�>_�"Ra�t� �!����9�<�X��]��o�jc���'`��i *��\E��T ��dId�;��rW���,z�x���ޔ��@CL�����=$ )E��?e�k�^(G?��؊�]�c��)+�]�ۇ"!#*�1�,��Y�G"��٘����7b� tk�.\E1��N�:�cY�셗B2�\�OG�r��(��Z?��-�) �����0I믋��.[AUn�)5(���r�ō�I;"��4^�m +�~*^2�뀖S7�lnl�1un� �R�;�����%6Ϝk��n��~�����^qX��T���ˆ-r�bPm�+P��͒ij��JYM��i.�^��<��u��)qwpɔ�U�Z��=���5�G�1��.:4�e�! �B�i�� ~�x�i��m +��Y����qo8-�Y��6�?���4]E!���%���x@x; !���u�iH�k1LF�`ˤ�"7��3�ޘ3SϪk+���MV��_o �BR��� Q���6 Ī���2���8l�+�+y�R��D8��\�U6 �/on���E�70���5 Y`r�>��H<4�/K�l�+y����~5�9�% +Q�Æy-����,J� �qt�q��� ���+�gr�4���Y<���6��O�Ư�SʼnX����bZC�2,�����o�bۤ7;ف���@�Q� ,���QLA��ᔅP�x����} ��>�Y"0��mq�Y�?� �&��l���j�1�v�K샹� U� m;� +?�eqC��\%���^↳S-���W�~���&i��≏p +�E��߽{猏�L�n|��=���Wx$v��� ��?"��Z`�F(*�S���_�����#�{��Wd�����$��}�MR�hM%G>��fzD��~��0sѡ8< �ʇǭ�@;�,�'u�m��-6��U�4oX�D +�:�� +�R`Y�O= rr��$��ſB� ū��ƾ�Cb� ��Ja�Q�&-����8&6����P�ฤ�J�6b�d���� �FHB�$hf0}I�Hɮ)4�8�I��#  Ü��Q?�[�Ĕ�^�k�!5�YR>"�S�&��›���[��1�i[��I�f:#"���G� [2r1!��{,����gZH�kNOz��m,v����x����oZyQDmsL2,:5��������o&�8�yW�ks�c{�a��i_��r���]���,@5�6�^�ۜ.�����*kƸ����B��(W*��A{�����F��Cl������7`��Uq�QG�x�/#��c2���}��0h���'"��\��PL ��A�ݶ�h�Ƥ��J!"=��t��[ ң�Li*���TH|ZF%4��Z ��U;;�%���3@���` Lمu_��X�eƅ �!]��Na�U�Ld�#�?[%���qE�b�]3}k ����aZ*TsX���� ��O`�o�'��tZ�9��v�TUV��P��'�4� ���9s���\��� H���T� Eݮ.�����Hx�v�r`f��ʁE���i�F��P�q��d���x�4��oC +;׆�7�B횲ĕK%3�&�*[?R� +w�qLE��4�H�P{{���N��V,� j�߹��b%BR�jr�E|q ɝ��\�DƛEBa&�׍6����*��a1�+R' +9��}�m���IZw �����e��Cy]"��䶒� ~Q[�TJ��NE��F��@��I�f�K�;�y�0��T�?JҲ�,�&Az�q'r|�U[ɩ��^���- o�z?|���&�wXLB�Ŵ�t ����x���sxO�ⶦ�����G������SF��!s�d�Vr�_\1�~�7�, �"K +�w��ëo�x��Y���wv���s5A<)�}b^�%'�����|%WR�� L��<�=֞s��v3j{�(+>S�j������Nl�9QQU�'��e;��6u��/�7&��vRF��3>�o���!��� �[!�]�[�Oo_�j�N +"A��A�"h>��*XD�͢$��Xx����IY�-ok��կ�p���z�x��^��r�Ch�̗��2 �$m��~�D�~��u�Y��:��QZж����_N,�%U����W��?�c�@{��� ���"�&��w�Ӌy)|������@$�r��N���f� ��{��_P��\nY�����(�aq( C؛��GY�ۯ�������(Ki��V|v�|"�&o����)GkY�n�Iwj�oν��6d��Ћ�e��U��9^g�;�+���]�U�gF +�W��9�&�9�5���{���ۊx���<� ε$&�(ź�f2����J���w� opp?��p��T�w���B����wK��h4(�}\,��DnQ�ٗx��}����T�j�0}�W܁�vH�di7��6(k��T��Sd�{զ+��!űGi3�^l��s�9:��+S�D�5��m�7�����F5���$(� �o��q7���l��� �< �}�l_�F�����Y0B� `� � ��Y��_�����=*Y@�t��ѰZ�&���,�!�Z�����m( )ג�/�B&�����4#�X�M�l�?�BH+�p�C[dg5<6��{0QV ���g� +����������'��n��7F� +�O�9�yq׳=��B~t2*����$���D��V��X�M��r9���/��Ǔ��|�_������-4&�kۼ�Ɨ.ț�/���L�n����,ϑ;���#�t������"zRa)��9r��,��>�ka �����=r�:���N�w��d��8�q��$���%b!�V��ĴC��ᴒ���^�q�-F��΁�J��� ���t��o|�J� �. ��o��M����N�0��~�9�P"P�� +qGm�H�bb)q�������ii��i坝�vn�C���c �X��d��yҦj� [c�V#ɖ��U>���͊��Q�aC�g�� ���Ao��A܆�1�o���nΏ���9*�a`�k�,ޓ�����6>�$�����5�\`��`���Ww�nV��v>;]>0 �� +k?���a��zz��cx������&X�8F N�֚�5�5_}��n�0��y�=TJ@4�K[J�8A�^�,�,ĪcGk��x��&I�=Yqf���M��e^F�hK.>r\#�fQ9� �fQ$�^���S!�~)�[�ΐ�@�����v�I�{�L��p���`kL�< gI��� ϲZt��b�u$��r��ꦰ�UR㖐]�Xr����k���6�՘{t��wZm����p�h`LmU�%-y�&�:������>6zx�6�:yI�@������#t�[�Fa� '�߾�u�<�#{6S�M)�gƄ)J����„1��X����c�8�L�W��o��,��|��Ī�jv�l�П�6��uK���tm�1uH� H��b2L��IMZ�P��Ůu1u�ҳOt^�e�5�`�8�or{+S�� +br�l�aˤRU ~�%B.1g� B��>x�ʧ1W��^5���c��o�&%�l����y�J����ڢ��I��N�H8|&C�0*�g@�`�XK�WB-!S�&�Xg*�,�B-��������t�q/�?Z�`4����7- ��|�ՙЃ���dr����K�� �)�׮&�jE�ʇ��޴�8� �&�FU���'��Fc�;6�#߷ѹ��������cCZ���ߙ���U�P�=�TWB��҈OUd`Q=�$�GP�f�y�Z��3�Ҏ�jL�������/�V]o�0}�W�I<$����nZ����j�'@�qn�5cG�ӵ���'��'P��(���s���|�&�H�=�P�_ > ����H.I���Dk�&9Gj��G�qS��j2i�a_���yq�^5�bO� ��&� g�\�;Ԗ��2�2���yi��a�"BA^4�FK�/4�R�(1=Q�l��8�0)��J��ʨ +k��S��4� �E��I��-� �Ǵ eM���fy?Մ�rr�R뇔�����q�8v�)4���FT�M�W��l�Cs�����&<���;�4�d��51G?g6n��TvT��� ���׳��p*3q8!,�㹚r۔�,��+G(�[W��0��aթ`/O;�I_��`�ڟ� %��A�ĮT���u+%��Zuve�C����]d5 �Q/}"�=1ֳ��°�U�c���Ė���aXJ�[�S�0;�'7�h��B��d�?ۖ[0|6(" ��S�W�с���������G��Xmo7 ��_�v��.u� X�$u�.i� i��!) ����Ȓ&�m���^}o�Zo�/�O$E>|H�z����=N�% �����y�����@Ȉ�p*RhT�1B]H� �F�M�2U��p?���Ӓ( J�U��0�.]�Ћ���EQ�(Q��㽺�F��RX��x�hӘ�� +�q(�6*��N����9� +�i��Mzs���ԳU���N���qpB������kWH"2��U[�1s%��] ��!J�_S����r3��L��!<�V?. LE�#��P�^*���\3�����߸U�gGG�|I�2�_���n�Lp���a�W��U0��*�N��+$�z�{�b��|a("�-,��~c)�m�F�X��`�<��k��&��q�)Tk4��w�^(��μ�^�wQ�}hd�ڶR�l�P2b3'���{�����C�9�z� m���$o���?c����PH�y� ���N,dJS��len�xr.=[��()t���́8��6{��̢<��F��Ʒ=3���D*��Wɞ~��~UP7��QM�8��׷qm͡l0�e����(�l+��z��[rm� ���q�z "�pނ�k�M����Sv���jKk����Vr�\�{0H ���d�$�̓Zz}p_~��ԍnU"�b�1�������E��IG��fV&)�Kt\ �������q� i��9ll��46�WbÆH+ ��| _C�f�m$ޢ��ff��ZY{1'؃�u&��n�&V��<�d Fn�W�z������t���1=�X�d�)�k� �d9� JF#�1c_���ݡ'۱�SJEfs��ܠ�j �Q���r*�4��Re 7�3:��v�q���`3�_8� ����Zݹ��i��4���5��aY0s�j�٬�S��F�u�hQ� +0��I��ׇ_.��<~��⏳�d4�xr�<8{ +u�LWGH��IHϤN��ho~��h�og"���+9�mHLre]8��m� }��i�ϰ(���btI��6lkc�se����|u Oộ9�����0x6QÓ��U���#��R� `r�Q�Z��`����y4ʹp4��1aC�C��5��������mA�1�S³<���8h�)���&���J��9�3,�zU/9���*�k�8g�D�����K�UuGTF��]�kM�a�4��|��, ��:�Ba�#��5� �<��%��� +��_ �-��ɪCˆ�Aǡ8}w�3f�M e��}oq���R�]�{:��V۶�!*������k}%��F�!n�b���Q�`�m�P&Jxd��$1�N?ĵ;䕲f�6%L����ܜ7x��y~�/��U�M@�����{J��U�(���ވ7:ZQr%^@[���?���7�# 7ūbw�-��0�����Zmo�8��_1-r�\�N��.p���b+�P��Jr�A���y�EI' v����_-����, g������>�F'gϟ��s��葑�����/���������~�Lp���M�}�N�փ�h s��?>���>႑۽ 4���H�՛["��v|Dl�2�?� �Q�l��$������1zO|��"b�aC��>��<�D��j��7 .�a�@7)(��v{.�a�H�آ[z/?�� +� ��Ėp�OQp�WP��{";��hHX�K�&b��{�]}��w8��)C�g�[�`�f<�5qjtA���KL�XI���*��3O�Ǽ(�)�z�[,�A�>eK���Q�!6���cF�Fw�E8݈�p�,u3aO�D�H�cҽ���8/h��M�½�mLV��ٜ38�wn��Z]��ǹ sk13l�� ��ҵ��k�<�0��j�,g�/���me�� ��ja3��m[_����\N뙹�8�󵫬i��0/Mט�k�bhF�`�.�Ұ�s}�����t��� �]J�� :�t�5��nKN������3ә.t�Ҙ��\��㳱t���E��`�Eu%�s�~�0bq�k���1u�f��ԜKW_��YSS>����n_+ -[�1~]K��0�/���Z�@��I��m�R�.$+g}�v �hY3eyǰ?�S�y �Q�[;�f������m]���V>��S�O�2��a��kZ�!̭+�a�T_;�L��Z*�ݹa�ג�4���\� wn�`.U(��ӥ9�6�n�Ҳ��l��,,�� 󣱜�%]��1T�e���1c�W�5Xk�����cďw�����gS����KX�c&�c]�����+�C��o��e�� (��{�[��r뷣|ȣZ���>��!W�Ν,�1޳e"�ap����}Ma�''r� �aJ� �K�ɿ��{$0��kO�����.�c�����aOPF0� �У6l��{�� $���ά�;h����IB/�+�X���8�F�&��{����aKV{Iΰ��m��o%�F*��,1�#L`�^,��E��S@B|�0�x�5|�h��y��0]���zt�C��� z@lw�D�3ԉR�=r�k��(h�uɐ�K@@0���|$�e;�d�{�� ��Jz��"��+�~i-�6���[��0� +x�����:&0h0G|�w���5��9�� H��wH����r%��$���~���Q��M@�=~�}�tWZHR��j6��S��͍GC.���.�����G6R���l�Żr�*x�Dm#�����n,&� �����`��k���1���g{��nIxV�M?ڕ�X���V&-ZTNyP_�󢵵��-"�S���vWV°س�QV_e3V� h��{2��uu@�(���62���G�T�W�6� �d��!AL ��Bb;�^ju��. .r{���)��h(M��\ؽ���w3���0Qg4��o`0tB8;���wX�r��૒ ��4�.����!����@V�5�{�N�=S+�-르��{ #� �{��L���O�Y��i���-pf*n6l��˳ �[�#Ys,�8�K7�$l�#OS¾�b��Ôca�%�I�ۂ=ςS¾�S1�ػ���Z��>$#U.T�p���l��,��Dƹ] �����ċ��m�n�0pzƿb����r�Z�a�xkeC�Z+ǔ�m�V�uڍ�q]�ӎ��zZ׃�/�����jP�;r��sWr � � �;̈W8�g�@#�V�N�BW�[�`.؍L���05plH~��Ty�T�1����΀���3�¯�s_s:��,�L�Z��D�6����5��W?�ޯ�Z���5O +nY^X\ `�N��G0���/�ʾ���S��>v��&Y~�%�ޜ��:���q�8��)��f�����;�4�98#I�$�-�:�gh��CE�3gʸD�; -ҪA�:���PdH��*Q�x@��xs,��K4�Ք%�BK�_�� =�ލ�7G 8;;h��sD3�b��@�w[(;��q�q( G��O���"U� �N�ᴐ��ġy+� +Y �|�Д�SE(�C�ZT�(Z ?)�z��j��ӷ��s�̤f8��=�Eݻ]iU6u�Ӧ�8,�>TL�3�f��Q�^�HټT��!�D���p�2-���� �����1�#R�YC��oN^[�Ք�>!�M����GiF���?�z=���?��<� ��e�A�����= +���;u�n�`�1��#��h�|��&���}Q&�/�d]��ե��tV̻w��6�6�Zcs���/����cƱ�5����۽��ۿ$�g���+ +H-K7L���]�6�~���K�.�6���8; ewamG�z�k��QӮ�N]�Yw�&�[O[^�Ŋ���E��6.Q3#�@.�[ŷ/|7�~ղ����gU����v��LH�w���K��\�= <�n�<>��DT f��*`<ِ��� ^�K[]�� r/����L��f<8KG��8Wu<8�LXEQQъ�f� f1��HM����`,�`�����h݂�ʿ�3𱐭_!�2<��Ƴ���]>ޠ} Z�R��5�%��m��~z�´���;���U�? ��V��������JM����ss�o���Jw��R�2Q�G6��Ob����;i �7����-|��&��������uo@Gq��$m.Z��ҦD��*���+��ۡUz=Z��B���=�XA�mɿ$!5g��:�|��~�T^�dP�o���/��w�y߬!v�H�����3�n�����+�ZE��]N�m(���643���e�ʀ���3�]�}�z#[sd5�r����4llU(b���i2�8�P'W'Of��1��N���2��wn��"_�W��7��M$��.����� o����k�G���1�{Ӵ�L;�$=em]ž3�{S�A�n��� U�5R�D��s���t��c��q�]ñ".d�w�@���i��S�b�.�f����I�퀕��n��k� a����'��V]o�6}��� +,N��u�Ú��,�1Y�D*���"]�DeQ#�A��>��%����`���s�=����?�Y�9>8�����S����~ޅW''�:y�;x�B�Y����6S�_7�G���^Y��֠P����8�Bh����YAV���-*Gw�ZT����Ts݃[af ��� sY���3 г��B�Qͅ1X@��(�3� ��T�����eU��]�͛/��ANR�,� m@��D�`�kyc5JU҈{K43J���i��'� +��2sTGϰU[��M�d����"�^ �/�X'z�UűT � �3�Jd�~���n5�n1B�rmL���{�J><�+�K,�tCd���5Z#`$`UH��z�Vr. �R&��@%n�����"ZN�m��kl�k̭ϠVºOY{UK�i��)���� �I|I@|H��Ǔ�^ 9 �0 / +��#��~����ǀ�=�x��h��8!�A��CJ��ċ8%�4��4��E�)wj�B:����ޒْ �F$�^Ľ> )����#[q'���K8���K,�8M�1#`[ (�C��Hp4�(rI"l��֎!N��Z�>��z��,�EhB|n;{8�i@"�=`c�S{Bޓ�8����0N�������S/��y������c�� Y���B���8�)'pǁS������B3'\�H�{=�|���٩=琉Z�,�8I�t�iua_�K��樓N�8r=�!���ŵb�Q��jH��$@#�[�<+� �y;2N�� o5 ���|b���2�u�J(�1tY�ʛ@�����RF��-;��h�� .�%� v���+��`�?\�߬��:˿f_�.+oad)����f&�[n?�F9��~"��� �ȱҎQ�./;pp��=��r>C��>6��{�cS����Ť2�RfZ���;(�.�*��� �n�9(�{!�Uf�oEXe�'B8�c����o�W�ms����Q+q��.>ڜn>+��tKn�7Xn{�m�� S*���cץ�a��r����s.+m�"7���^QB݃�u�F�����������]�{gk��m�m8���&�~7�Z�����ũgp��T*�����L����;x1%>�����/���Tt��kJ.��n�kS�ey�����F�}����k=�gz[����~�F��ȇe֧���oQ-�G4�@;��N;�a����v�l�6�����˗� [U�� ^�l��̔�� +o��u�-�ڒ����W�p��T��2��� ��3���z?�|�K9ʪ����!u�����h���������9�X��l��&�g�lYJ뒛^�T`���6g,i|���ȶncnv��mGƒ/�y ����`Uh��p���p�2�4��o�]��s���Y[o�8~ϯ8S�p/�>m3�V��XXE�Hr2�tl�E I%�m���DG�d�}X����|�;Wʿ��X'޾=��0f����+��������O������ߐK���{��}�J��2��8 +���? bJ�������@�J�@s�� �_�iN�,߈!��+�M��%�̍ +��:�F0�kw�L`t �́q0� ��Y ���8a�?�q�ǡ;Z�A�;7z��ǟ��߂��������\?v�p1����,�q����"r&�ׁ�m�gN�*\� �!�̜x����+���Q�㸹3!¸a,�Υ�^:��Q���q#g�S+t#�ǭ��ط,��:h�ȩ>6�y�C ��ɵ��W�uJQ���L!Z�g��Me|)H�P��]J�1���I)׌�r;�D���Վ��;��KF̅f4�&�U_+�Nt�)H��1B�w�6|?9QB�2k�1��?E ���^q�$+St��oS�I�DN$�g��$#B��h9�C��Ym^o���0f���?�~.8} �4�{�^"�_�Q[��� ܵ]yWq4<�u��M`Y扞�J����y8U-��E��/�� ���r�%�a�GQZ�{��fP�����,Mh�3�������X �C|��jG�Pzl�Bn ��Ϋ��S��``���w�hywA��%Ey�R�?�9���>�vw���w8��M;;��V����'D`�{G�a�z�%X�tty99��0�mV ��w1���I�4_�b�J]�� �[��[w-:�~�7�� +�h���q��4�� �e���ӥ�!���2j�4C��mI3��Q!�U���D�I�$pe.��K���� +�W5�b��{��N8'O}d������6 ��X�#��pl��Y���`�n:���0{R�]41ː��n��RH���X��YS��t��QF�o�����K���VW��pP]��z&VԷ5��1m������epZI��h[ӱ�Zo�jh8�8\8��*j�U6�OE楪���-��݅@YK�}���KV_��`ԓVF���x�n'�Tߝ��MF�o����Иfdeݩ�$��č��>���|�n�<��wtT��go5fZwF�N�8n���xhR�j��>�f�~"rMi��cf�5"�45 {�`ˋ��- �v����F9���0+�3&���oͅ$�1��GH%'�}B���@��W�Z�#tC��_H�� +Q���+F�{������S �M�V�g7���S˨��]�T����wE��+����0� :}��!�[� �5OThr�Y�=�wp��Q'P�MTCu�P���K �%����J��{���vK�z����ժ�R��k#�'�� E���WG�1�~��>�gzk�F}uo +���u��Ƣjbֶѵ;��=�R�{�m�}����� _S�-�[�������S֛K��9�_���_!e��������Z}'�=��iw�R��B���_X߹�ʁH���>�Ԓ{CUnDbL7��Sv\U��w�� ��wGڣ9�8�o=j�^� ڞ�?�]NU�y�zjr�$+����2����6�S�,��8�7�R����?��X�3������#�y`��LҴ:�<��'ܥn��><��<���U�o�6~�_q(��jdO[�.�D�d�#���D�D%�#�A��} m�n�}�^�w�}�ݑ|��n�]�};����ݳ՛��qu�WW��������L�}V�;x/m�nW���V�7j���r�>��b��Z;o����t �z�@w�Lo+WV����ƶ.�'��`l���Ckj�֕ I��V�N�V{�j�Y�kU��J~�`m��<�n��j�\tj���� �����R�����`�����re�֠Tg��T�G�[�������]��U�]�H�*{�ltw���fgM�W��"�\kS���|}�]}i,�UZ�ղq���E�DNS,������� +�^uXg���@|�e����V*4R ހ�jc� +=���5^�^&�VV?��ִ{E�Y�'i�6��۩*���gC{u�Fs�$1#8���0 F�I�3�,A�0�t�d�n&`F� 3�� ��`dR +�8�AO�*��?.�(2_�g��C� �'@�4/3R�%0)ET� +�ɜ���ɞ��3�)�1Kg�hBr"�1ꔈ"D�R� ��9biQ��B��i��g@ +((�{\�3����(;M7N0�Mr�W,!# �"dv�$Å@y|�S�#�/rĖ1Cʂ��Y�B�C���s��:�Hi��<���� D���YT�cvOR�o �< +Wr�@�J����)�&�'%'A��E +�+���f��c)*9΢ִ�9��lp�� <̰�a��Wq9�`$�����L�$ ���.Rviz ���b�����@ː~,Z��~x��I,-�)���{���srh:^�����ɸ���ܨp�P�Mcd�e�����s/���V� ��G/�6�R���&<�|?���[f'+b��R���6|��S�H� 7����Z�vV?J����^+���� ��:|Q+[X�|�V'�G�~�� +�}W�7�ӧ�t�۾�����Q�,\r�> ��7����~�1��Y�������va��h)^��k��{�>�|o����_����U�Ƈ` �Ͽa�2z��S�n�@�����6�nkk�������L�Q6�e3�k���A¥�v��{oO/:с�=���+�O"^͝�� c8�H��@6� �R{�(��x\�a �d0���-��Ť:k��#��5� Ȍ�a4��)� +� cC�� ���u�B_�ڇS N��@5LPF��#�Ў'�n��b�f���h����Ɔj�������:�O�a(#KS�h��p2�F:p<��4u �ڙf���ND�*� � ��F�TYʱ6Ԭs>�f�p��Ɗai��P1�xb�uSdq��������.h#�~TG���p(�tCd�0Ԕ� 7:��f�} 9˾���:��a̱������z6*�9�P7P����:�4e�L����*� ����Pϐp�Q��c�Ҭ���]pɛ��Q�� u� nb�(�������h�y�ߏ'���C\��R c2�4}ԆS���Q5��LLu�e��8�֩�������NU�T5@qS��SP�eh}K�� �t�����a�}PG}[uD�I3�6W-C3F�����>A���ML5�*�s�O-h'� >jH|�UB7M-V��I�4�~�2ޯl�ƾ&���ux�=���u�(_n�y���U۠G���{�u��8E������eog�ۘ����$�~N��/;;�eoƧcx�} N�\�!;#s�'��5� E��o^7;p���͛�p��zA�R�f� _x�G��qﯹ����GpgәHCq��r�NO&�����e��h�jD)�@�Z +W$�`B��䬊0�&c����hg�x6c�q;���Z�/?w=�b��OUո�Vԕ��㟜hGܹ˕G�'o4?$t�R���uo�@cI�E0;�W��R�����k\����+8��>���`�o^o�*��!^�j(���zY�۳�}�T��}��nn�O���O�V�G 7�E�T�J�~R������ ���ܐ���._j��+��>1��S}��6�1ЇC��]��dž�W��!���#�…+R�n�t v�r"�A�Ze����$Qjl��Պ���s�،h>#>sC��Hn�� �)�RT��٭4�G2���qk��O�z�/��%�)�\E�CrK� +4���h+k��k&�� fdE��7��HɌ8�M�(3����\�k���t�> �� [�9��tMD�O���we��']�f�����l�vo��]z��ۤid�s:�-J�R�g:���M�%��9� �����+��?%���ak/��*%�}h���?�x/�%6��[�^��{ #���-���=�7a��Ka�'��#9��9n-",�^_���p�i�����t��U�a����D6Nyn��؞7]3B���[��F��p!s����~䙉m�O�D��mA:�h�;rSЖ���d&�����UX$qտ|y$�{�K8x��$���|n�tGs�c�����͠D�Xr�B2-�f���^����%�Ilg��)��R,���،�x��;7t�j�����J`3���~����:�����өfE9�aŠ�\Qb�ȝ����e�Zz�E�Z�(^�#�M[��qp)g�Q��5��:V �ҍ�H���}:��,u40kI(�(̈� I5>��h� ^w�'���7�<��\⫩ov�uDs���SR��%좹����-%,�n� ���¶��j6�Q�缪��s=#s{�u� +4��"I��;d����V���y��-|�Q�M(��O��naf�q\;� 9����'�+�|��������O�Չ��-Ԋd�˦.O�b��+|昦>����!�_k�;E �*�Uٵb���# �y�"�Ͷ���D��矓�$?l��ۗQ�L]z��$�K ����fi�'�l���HL��q���P��[Y�N�]�_�nJkb�v�u�s��IV#����j� 4*�^L�� a�ҍ,ɥ P�'�Hz����X���cI}��� ۯl��zXI�i���WD=E����::>���.;F��j���W$D$��B��o-����������Hq�������������ٓNOٓ�҈����9�?g$�{�G�,F��.K�����a��D�ߒ.��=`凩]�s}~�v���u���Rw� ���� �PmK1���?EкI��{t�HeD<D ����@�g�NO+�n޼G�� \�l�RZ��6D$���]JZƫ?G�(W[���T��C=��l<U���� a�5�T�/�~A�K���� i��E�@�#��LK�2E��zF%���{�x +��"��r�sB��,8j�הS!�ּ�̳����!�>Ӹ�G ����ރ��9�h��5��G +�Ң��alr2k͊�[n�b�v��w�Pݞx�mK����ǧٿbȱ�ы�ם�Z��~R�땬O�JN��yD��& �ME�o7�q�[�(I�[J&a����3ME��OŎS�����LE��8�Ēs�+]Uq��4|Ƣ�]�[�NT�{�D%C�x-�D��&#��4�#��zY��˞ںq�h����~�{�'�+ ���#"�'*��_��k�/�s��Ҳ�"�-� μ��a�������G�v׷�SB��6׹l+�������N����2X���5�'��m�~�n�+ۦH��w�J�v-��եPZU?}��� M~Z���Z�W�Ǔ6&*�1L�!��T�Uɮ��애`Q�/�M��b�_w� �Q1N1���)(�%HI +$�%�Ʒ��plk�N@����%R��V�3;3^<�>�@{�D����Y�W%G��3k�ϗ:�0�� Gt.��Ђ?���h�s�[XO��8�ܻ��'h,b���xI%�Q0�Jc�)|�dł$�r{�-�W���Kܮ��AL��u]!�,n��̸�Y���Ku�t鿍�T�C5�;w�P ��2z�.E�Ύ'�B.kM�rDOTg�e"�=65�ǁ��O�f�Me�EW���?u{}�nn~�/�R�n�0��+� Ĕ�Əc6m�қk CG$R�]� ��{@ٖ��Q^4�.ggfu}S�U�Ti�R�������� ���=�t���Nq~��J�b��Z8����0��/ +��{�l;�E�+�/� �O�f��HP��M$ٗ� �;b��U���%��{�޸i]�ca5�j��z�1�H���;�F�\�\)j� {É9���G�{� hTQ)��$W��,�=��N�K�φo}Yz�[���vB�ڱkH@J �)�h�Fg5��P]0�)��m6�٨�lr�����*�ez��whv�U��=��D;.2���x��%p��f����v =�*���0t����0NĴJ�Ay�-��e+����-��-\7�p���j�-H�8��������+O⸆`1l�&�(�C\�'�XQo�8~ϯ�9�)���" \�I+[LL�#�D9٠-ZDŽeR ���"��@ٲe[��N/���Ǚo>����K>��>~�P���|����B+9��O��}t���7�D�d\NQ[p-��z>N�B� J �'L��c�I��0V�Qa���e +�A�*t�囑�\�a��̴�Y� (]����L�b,��.�9꙰Sȵz)�`'܂� �U��g!!Q2n�)'�Оm���5�LT�0+��� Y��zrC�RY�`{�`'�@&�uXu'd��a*L�q1C��^�gB���<˵J�����2�T%� �-R�2��4(;A 3nQ ��ur�Ė���BP��V�:'�T)�z�,�X`*m�N��F�D��U�2Uڠ�W��LY�u�@�Zt�!�膃��^�b�}�D ���n�� �0b��c@��� |��{  "��ЛA��(��t�C��m� ��0�>��1�!�kI�WpC�n� b�C�4�/W��q�V� +#�`�E1��^T� �� d\�>eݾGo� 4� rK�X�����0��^�v����Ų�=�4"��E���R���o�.u7�/r3�{��*�0r�2�! b����n�k �E�[.q�aDn\�Udž�x�C��#�-�v���Di���^ۍ�������w��:>+<�$������!��;rK"�zCF���0(�{$���#�LO�z$�h�*��L����v�uAFq-p�u�^��K�h���(#�+�E�9;�p�λ�p��(�9ddq[�|�L9�+��[�X��2F�� +�� ��eF�w�ל'S����+��OWc���˧_�d_���f���|�5 JSz�a>���1|�++W��x� Q�B���J+�(�1_hL��s�p)^�/�$7�;��R���r-��E�7՜��D�r�e�j����LE�7�aØ���Bc<����t�@�����a��)�\i�)�C�'�f�������'pq �Qgg��~>i�ڝ���ewr�{���-��+� ��Q&2)C����"���t�r�^�{o���Z����.�Z3[�8��|���A�]K�F��ڟ�_q�&�����e6��ڷ�|g1��;!i-Mڋ?LqnZ#�z8<�ƃ�$��3H|��T>�L��~,�7�g���3�]&�B�q�`� +8�����{w䂩T��4���'�g�AoB˳��n��Ru���̧�nt�.���������i����jG��rm;�x�Z���+Fh�-F�#�;�������a��������Y����|�B�(���)���P5�v�pwv��J�^�����YkY�� ��#���7��.���#ڇt1T���I^X�,ʺX���b4Ź+ +�ž�W?�u�ld􍈫��&[�w[ �mQ��z�fs����is�� ?Vy2i�7�zݨ�X��+�fԢ�V��fw<�|x�IM�^�j��̀k"�78'�n�0 o�Wͺ����n+��q'���jE�!� 5�����Y5�BKx��~k���f��>���-��7۵hKD�� ��.S�:�..��QѲ>k��k>6� v6zps�[Z���q�6��66/� ��K������;W����-dȍ��L�e�SX��:9�Y6���}���m����.�D�Ǎ��x� ��Ow�������_=�� +�@D���-,��/P�NL�@8�Ir���=B�]���f�1�?�!�/�h�Pcs�8�M�9�)Q��p� �[!�DMy .҅?�(�;{G]�>��:iʫl +M�^$Ɍ��Wɭ�1̣����;Hf���.�׳f��(7�`ID'�$�b8rc��m��7���<"q a�f�S���En�P��S���z �Eb� �� M�I8n���^� ��37H� �irg�^�$0��\��QB� ߍ���"��1�G���� �|#A�����C��5'|�N|Ҹ ����&&��Ӕz$H\ �L�y �����Fw6�02D��_ $���so�k��C�;&I�EDn ��ʘ��8��"!p��e>&�7:%�9�al�[�d ���c�?��+����y�����آAB�h1Oh�`ޒo$�����g�s2#atg�2l*�p;#ɌD@;� q��#N":M��aI%�`! �>�&�������1�Ҋhldh��ֽ�pa·I[Ĥy��ئ���7j�7¶$�8�m��W/�����3�V,��д�[kQ��uV땐���w�|�N�wh��:��k�3,�E4�=��|8 쌩X���0F���@ß��Q��#��5�y�+Pf$f �Kl��R������K-���fZ�ڝ��JD����am��߬`JAlC���Q����2W/�{�h�0����s��v�qT���Պ��k0l��[�/d�Qo�l1�\�NO���#5âB�3]���`Y�����i&J�e�i�Iɞ��rb�9>������Ea�3��>;�[����>6���˾=��� ?��N�Z����u�x���ĊI��6��=��d�h��`8L�� +��+�}q�KNo�`L�9V� 3��'�nn�ؓ8������F3_1y#rt��AX���"�i �h�>B�{����{p��(3�A٭�3�6~b�X� �؏�y�v#6>͕�|�c��`�M�u-�V�]ؚ�w^,��z�P?��&����]����:;==:�R�a����o�4M�37J�t����N�赳g��|�l}����ĺb��0�Ҝ=N�^Q���N`g0LS�Fij^w\^3��Rl;ɶ��3d�B"�VL%���ΡəO��z��<4ѻ7�c��&nLl�;�]弭�.���6�K�K�ϝ!k�����q�g�����uζ����kN��;>)���h�ftÊ_�o[�=��=��S���ꔗ�e�~�JƵCJ�~�r 9Vyw��r)~2����ؿ:���G�vV���@2(.��G��[��nv��F5>t�^ �m�A���e%E�J9o��I�I����u�e�y0x���MK�@���s(ljz7ֶ�AZ��e���d7�����K>Ms L�}g���-�ch��-�Dx;��vk�LfD��̄��u�)��O�_�u�)���0G�Z���9�Q�� ����ͫzA�$��[|��n)}�J���?�Li����zC�B�Ȼ�M�9������t�h�\my������ʬ�f +�:&���}�â':@꜒h�@�_2=�����'���O1�v +"�U&[we@��aa���@i �!���v��S�0��?��O�������C��Vl���=�+�O�� q�Ӛê߬����L/�7�V�N�8}�+�F�ZF- �i�a�4q���tm��J(M\jMG�[����ӆ�����%�}}|ι7v��Uͫ#8���y�|]=�8��f'�8?��q~�v���q���ʑϞ���{�Ƴy�L��!����'1Ǐ�� +�_�u;�^,ܭׯ��sYgFM%���xJ�k���2�_�r�:+�E���x�u�&�%G�'Ήc�5��L�A��Ø/�Fߎ��i�������N�r��5�||WI�N5��):8�����N�A�O�_���߬�S+��Ig8}��6]������������u��j�0 ��y +zH`�Е�K3��4= �&VR��3Y���>��R��ϒ>��n�%�)<�^�V��V�C�:��d,)���X�4�JKd�7L�@��[r�JHCc,�-h� �6���b|d���Ԛ �i����]:�� +!���rL%��P�9���ى��3��r@�E�bV_�� b�ZTժ�v�8��y�!9�t0� �$>���L$'��I�޲k9���0E��EU,�-"�Z��n�?��%/6��y����f[l��2���������]�Mk�0 ���:b�X���Y���5I�1���Ր:��0��^�|�= =Hz��hN�8ӡ|��� �|W�KK �qЭW�����1��m�8/�j� +����u�����+�/�M k�]�D�ʴ�ˢnq��t�B��pކ�>��W_�)��^V�~e�rV~ �J��I��z��|�V��=,foE.w�O>�r��="�M^�<�?�XLxX�9  +�ΰ� nӲ���E�W���u��J�@ ����X��}��hݭP(VlA$ �lw`���T�w�Z�?�2_��!����}�Z�]�q]-�i�:��L��Li�?�UG�E��L�&� ��A|G�X i�Kp ڃ���D���b�D�^����-"Ƌ֪���(1-LM +���]�1���� �±�T�Y}�G2"nʬ�ˢn�Ȓ��MR���"���H�9��{O�C0} �i\w����xFċ�y�! +���p�+�L� B///�����M���#"&��;�u��j�0 ��y +vH`�Е�K=�.4= �&VR��3[��w^�� �?}�>���c�,�X;�m[��Jz��:O���?��}��- �b�92>�:�� {v-Y�IA� �(�1�Ҝ��`�d�T�Ձɧ @�ۚ���Mmd|��cK�5 �����,G�H�p5��1��{��Nh "��uUm�ꀈ��m��W�@<�߆�{6�{�赧�xZWbS�q�5w�n����k.�C�CıX�E)v��j��r%aU�]��J�0��y�9M@���EJ l�Adݬ�mL҃Ⱦ��J���c�����o �!���'t�C��%�k��;z��=���u�2�F�<��I'��@op7����ٵtN~��Aļ��,���lׅW{��d�w��;�5h� �鶛 "�}V!b�>_ˮ�� ͹h���������ؙ�DD��S�8�dfb)A�ge���E%�(K�/u��J�0E��� l �~��h�V(+�� 2�f� ��&SAd�]bٺ +;O��p��f܏�z ��S���UҫP �y�׆�� +�A^4#��sd��tiAN���%��^�+P�c �9�'۱v1n���w��^tF���WX��`>R�-�ɘ��=��`;��0ΉJz/?Ӆ�AĢ΅�+�"�²���d�����yy�N�<�O�S���E������{H�h0d�T�iЁɧ��M�.�]�R��m�< b�9�Ҫ�u�A +�@ ���"�~@P�z[�!�t(Iٍ}��x�y`��}��0���VK�157�t����iT�G%���b�ځ �^ŤQâ����<@X#!��q�剈'�h�>��/�(P��W(��,V�,VH�SH,-�OO�K-J,IMQH��IU�UH�W��/QHM�,኏�w��q�� ���犏�p� �w�� ��q �д�4�����`8`��[����X Ž �d��:Fa���V��d2��0�A ���p��;���)�QGBMB \ No newline at end of file diff --git a/tools/phpstan b/tools/phpstan new file mode 120000 index 00000000000..5e15af476e4 --- /dev/null +++ b/tools/phpstan @@ -0,0 +1 @@ +.phpstan/vendor/bin/phpstan \ No newline at end of file